Skip to content

Commit

Permalink
Merge pull request #210 from scottyw/foobernetes
Browse files Browse the repository at this point in the history
Foobernetes example workflow and plugin
  • Loading branch information
thallgren authored Apr 1, 2019
2 parents 1a07338 + 79e42d0 commit f58685a
Show file tree
Hide file tree
Showing 12 changed files with 738 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ build
tmp/
LICENSE_TMPFILE.txt
*.db
deployment.json
33 changes: 33 additions & 0 deletions cmd/goplugin-foobernetes/foobernetes/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package foobernetes

import (
"github.com/lyraproj/lyra/cmd/goplugin-foobernetes/resource"
"github.com/lyraproj/pcore/pcore"
"github.com/lyraproj/pcore/px"
"github.com/lyraproj/servicesdk/grpc"
"github.com/lyraproj/servicesdk/service"
)

// Start the Foobernetes example plugin running
func Start() {
pcore.Do(func(c px.Context) {
s := Server(c)
grpc.Serve(c, s)
})
}

// Server returns the built server to be served
func Server(c px.Context) *service.Server {
sb := service.NewServiceBuilder(c, "Foobernetes")

evs := sb.RegisterTypes("Foobernetes", resource.LoadBalancer{})
sb.RegisterHandler("Foobernetes::LoadBalancerHandler", &resource.LoadBalancerHandler{}, evs[0])

evs = sb.RegisterTypes("Foobernetes", resource.WebServer{})
sb.RegisterHandler("Foobernetes::WebServerHandler", &resource.WebServerHandler{}, evs[0])

evs = sb.RegisterTypes("Foobernetes", resource.Instance{})
sb.RegisterHandler("Foobernetes::InstanceHandler", &resource.InstanceHandler{}, evs[0])

return sb.Server()
}
19 changes: 19 additions & 0 deletions cmd/goplugin-foobernetes/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"os"

"github.com/hashicorp/go-hclog"
"github.com/lyraproj/lyra/cmd/goplugin-foobernetes/foobernetes"
)

func main() {
hclog.DefaultOptions = &hclog.LoggerOptions{
Name: "Puppet",
Level: hclog.Debug,
JSONFormat: true,
IncludeLocation: false,
Output: os.Stderr,
}
foobernetes.Start()
}
84 changes: 84 additions & 0 deletions cmd/goplugin-foobernetes/resource/instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package resource

import (
"fmt"

"github.com/hashicorp/go-hclog"
)

var ip int

// Instance is a virtual machine on which the app or database can be deployed
type Instance struct {
InstanceID *string
InstanceIP *string
Location *string
Image string
Config *map[string]string
Cpus int
Memory string
}

// InstanceHandler is used to perform CRUD operations on a Instance resource
type InstanceHandler struct{}

// Create a new resource
func (*InstanceHandler) Create(desiredState *Instance) (*Instance, string, error) {
hclog.Default().Debug("Creating Instance", "desiredState", desiredState)

// The cloud creates the resource and allocates an ID that can be used to read it in the future
d := loadFakeCloudData()
defer saveFakeCloudData(d)
cloudAllocatedID := fmt.Sprintf("i-%d", randomInt())
d.Instances[cloudAllocatedID] = desiredState

// Update the desired state with values provided by the cloud
ip++
ipAddress := fmt.Sprintf("10.0.0.%d", ip)
desiredState.InstanceID = &cloudAllocatedID
desiredState.InstanceIP = &ipAddress

return desiredState, cloudAllocatedID, nil
}

// Read an existing resource
func (*InstanceHandler) Read(externalID string) (*Instance, error) {
hclog.Default().Debug("Reading Instance", "externalID", externalID)

// Read the actual state of the resource from the cloud
// The external ID passed here is the same one that is returned at creation time
d := loadFakeCloudData()
actualState := d.Instances[externalID]

return actualState, nil
}

// Update an existing resource
func (*InstanceHandler) Update(externalID string, desiredState *Instance) (*Instance, error) {
hclog.Default().Debug("Updating Instance", "externalID", externalID, "desiredState", desiredState)

// The cloud updates the resource based on its ID
// Update is not allowed to change the external ID
d := loadFakeCloudData()
defer saveFakeCloudData(d)

// Update the desired state with values provided by the cloud
actualState := d.Instances[externalID]
desiredState.InstanceID = actualState.InstanceID
desiredState.InstanceIP = actualState.InstanceIP
d.Instances[externalID] = desiredState

return desiredState, nil
}

// Delete an existing resource
func (*InstanceHandler) Delete(externalID string) error {
hclog.Default().Debug("Deleting Instance:", "externalID", externalID)

// The cloud deletes the resource based on its ID
d := loadFakeCloudData()
defer saveFakeCloudData(d)
delete(d.Instances, externalID)

return nil
}
77 changes: 77 additions & 0 deletions cmd/goplugin-foobernetes/resource/loadbalancer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package resource

import (
"fmt"

"github.com/hashicorp/go-hclog"
)

// LoadBalancer distributes traffic to web servers
type LoadBalancer struct {
LoadBalancerID *string
LoadBalancerIP *string
Location *string
Replica *bool
WebServerIDs []string
Tags *map[string]string
}

// LoadBalancerHandler is used to perform CRUD operations on a LoadBalancer resource
type LoadBalancerHandler struct{}

// Create a new resource
func (*LoadBalancerHandler) Create(desiredState *LoadBalancer) (*LoadBalancer, string, error) {
hclog.Default().Debug("Creating LoadBalancer", "desiredState", desiredState)

// The cloud creates the resource and allocates an ID that can be used to read it in the future
d := loadFakeCloudData()
defer saveFakeCloudData(d)
cloudAllocatedID := fmt.Sprintf("lb-%d", randomInt())
d.LoadBalancers[cloudAllocatedID] = desiredState

// Update the desired state with values provided by the cloud
desiredState.LoadBalancerID = &cloudAllocatedID

return desiredState, cloudAllocatedID, nil
}

// Read an existing resource
func (*LoadBalancerHandler) Read(externalID string) (*LoadBalancer, error) {
hclog.Default().Debug("Reading LoadBalancer", "externalID", externalID)

// Read the actual state of the resource from the cloud
// The external ID passed here is the same one that is returned at creation time
d := loadFakeCloudData()
actualState := d.LoadBalancers[externalID]

return actualState, nil
}

// Update an existing resource
func (*LoadBalancerHandler) Update(externalID string, desiredState *LoadBalancer) (*LoadBalancer, error) {
hclog.Default().Debug("Updating LoadBalancer", "externalID", externalID, "desiredState", desiredState)

// The cloud updates the resource based on its ID
// Update is not allowed to change the external ID
d := loadFakeCloudData()
defer saveFakeCloudData(d)

// Update the desired state with values provided by the cloud
actualState := d.LoadBalancers[externalID]
desiredState.LoadBalancerID = actualState.LoadBalancerID
d.LoadBalancers[externalID] = desiredState

return desiredState, nil
}

// Delete an existing resource
func (*LoadBalancerHandler) Delete(externalID string) error {
hclog.Default().Debug("Deleting LoadBalancer:", "externalID", externalID)

// The cloud deletes the resource based on its ID
d := loadFakeCloudData()
defer saveFakeCloudData(d)
delete(d.LoadBalancers, externalID)

return nil
}
53 changes: 53 additions & 0 deletions cmd/goplugin-foobernetes/resource/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package resource

import (
"encoding/json"
"io/ioutil"
"math/rand"
"os"
"time"
)

type deployment struct {
LoadBalancers map[string]*LoadBalancer
WebServers map[string]*WebServer
Instances map[string]*Instance
}

var filename = "deployment.json"

func loadFakeCloudData() deployment {
var d deployment
bs, err := ioutil.ReadFile(filename)
if err != nil {
if os.IsNotExist(err) {
d.LoadBalancers = make(map[string]*LoadBalancer)
d.WebServers = make(map[string]*WebServer)
d.Instances = make(map[string]*Instance)
return d
}
panic(err)
}
err = json.Unmarshal(bs, &d)
if err != nil {
panic(err)
}
return d
}

func saveFakeCloudData(d deployment) {
bs, err := json.MarshalIndent(&d, "", " ")
if err != nil {
panic(err)
}
err = ioutil.WriteFile(filename, bs, os.ModePerm)
if err != nil {
panic(err)
}
}

func randomInt() int {
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
return r1.Int()
}
74 changes: 74 additions & 0 deletions cmd/goplugin-foobernetes/resource/webserver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package resource

import (
"fmt"

"github.com/hashicorp/go-hclog"
)

// WebServer handles HTTP requests targetting the app
type WebServer struct {
WebServerID *string
Port int
AppServers []string
}

// WebServerHandler is used to perform CRUD operations on a WebServer resource
type WebServerHandler struct{}

// Create a new resource
func (*WebServerHandler) Create(desiredState *WebServer) (*WebServer, string, error) {
hclog.Default().Debug("Creating WebServer", "desiredState", desiredState)

// The cloud creates the resource and allocates an ID that can be used to read it in the future
d := loadFakeCloudData()
defer saveFakeCloudData(d)
cloudAllocatedID := fmt.Sprintf("ws-%d", randomInt())
d.WebServers[cloudAllocatedID] = desiredState

// Update the desired state with values provided by the cloud
desiredState.WebServerID = &cloudAllocatedID

return desiredState, cloudAllocatedID, nil
}

// Read an existing resource
func (*WebServerHandler) Read(externalID string) (*WebServer, error) {
hclog.Default().Debug("Reading WebServer", "externalID", externalID)

// Read the actual state of the resource from the cloud
// The external ID passed here is the same one that is returned at creation time
d := loadFakeCloudData()
actualState := d.WebServers[externalID]

return actualState, nil
}

// Update an existing resource
func (*WebServerHandler) Update(externalID string, desiredState *WebServer) (*WebServer, error) {
hclog.Default().Debug("Updating WebServer", "externalID", externalID, "desiredState", desiredState)

// The cloud updates the resource based on its ID
// Update is not allowed to change the external ID
d := loadFakeCloudData()
defer saveFakeCloudData(d)

// Update the desired state with values provided by the cloud
actualState := d.WebServers[externalID]
desiredState.WebServerID = actualState.WebServerID
d.WebServers[externalID] = desiredState

return desiredState, nil
}

// Delete an existing resource
func (*WebServerHandler) Delete(externalID string) error {
hclog.Default().Debug("Deleting WebServer:", "externalID", externalID)

// The cloud deletes the resource based on its ID
d := loadFakeCloudData()
defer saveFakeCloudData(d)
delete(d.WebServers, externalID)

return nil
}
4 changes: 4 additions & 0 deletions data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ aws:
department: engineering
project: incubator
lifetime: 1h

foobernetes:
lb_policy: "rr"
in_production: false
Loading

0 comments on commit f58685a

Please sign in to comment.