Skip to content

Commit

Permalink
[State] Feat: write current and desired state
Browse files Browse the repository at this point in the history
  • Loading branch information
MeNsaaH committed Jan 4, 2021
1 parent 8170c60 commit 9bcfd2a
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 43 deletions.
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,28 @@ cp config/config.example.yaml config/config.yaml
# One time run
go run main.go --config ../config/config.yaml

# Web Dashboard
# TODO Web Dashboard
go run main.go web --config ../config/config.yaml
```

using [air](https://github.com/cosmtrek/air) with autoreload UI features
## Installation
### Using go
```bash
air -c .air.toml
go get -u github.com/mensaah/reka
```

## Usage

Reka loads default config from $HOME/.reka.yaml if --config param is not passed.
Copy `config/config.example.yaml` to `config/config.yaml` and make all necessary changes

```bash
cp config/config.example.yaml config/config.yaml
# Run reka using configuration. Stops stoppable resources, resume resumable resources and terminate
# resources dues for termination
reka --config ../config/config.yaml

# KABOOOOOM
# everything gone
reka nuke --config ../config/config.yaml
```
60 changes: 38 additions & 22 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ package cmd

import (
"fmt"
"log"
"os"
"unsafe"

"github.com/spf13/cobra"

homedir "github.com/mitchellh/go-homedir"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"

"github.com/mensaah/reka/config"
Expand All @@ -40,7 +40,7 @@ var (
cfg *config.Config
providers []*provider.Provider
backend state.Backender
currentState state.State
currentState *state.State
)

// rootCmd represents the base command when called without any subcommands
Expand Down Expand Up @@ -91,7 +91,7 @@ func initConfig() {

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
log.Info("Using config file:", viper.ConfigFileUsed())
}

// Load Config and Defaults
Expand All @@ -108,10 +108,8 @@ func initConfig() {
// Initialize Provider objects
providers = initProviders()
backend = state.InitBackend()
currentState = make(state.State)
}

// TODO Add logger to Providers during configuration
func initProviders() []*provider.Provider {
var providers []*provider.Provider
for _, p := range config.GetProviders() {
Expand All @@ -135,25 +133,43 @@ func initProviders() []*provider.Provider {
}

// Refresh current status of resources from Providers
// TODO Reconcile state so that new resources are added to desired states and former resources removed
func refreshResources(providers []*provider.Provider) {
// currentState is the state stored in backend
currentState = backend.GetState()

currentState.Current = make(state.ProvidersState)
for _, provider := range providers {
allResources := provider.GetAllResources()
currentState[provider.Name] = allResources

// stoppableResources := provider.GetStoppableResources(allResources)
// fmt.Println("Stoppable Resources: ", stoppableResources)
// errs := provider.StopResources(stoppableResources)
// fmt.Println("Errors Stopping Resources: ", errs)

// resumableResources := provider.GetResumableResources(allResources)
// fmt.Println("Resumable Resources: ", resumableResources)
// errs = provider.ResumeResources(resumableResources)
// fmt.Println("Errors Resuming Resources: ", errs)

destroyableResources := provider.GetDestroyableResources(allResources)
fmt.Println("Destroyable Resources: ", destroyableResources)
// errs = provider.DestroyResources(destroyableResources)
// fmt.Println("Errors Destroying Resources: ", errs)
currentState.Current[provider.Name] = allResources
}

// Add new resources to desired state if they don't already exists
for k, v := range currentState.Current {
if m, ok := currentState.Desired[k]; ok || currentState.Desired[k] == nil {
log.Error(m)
// TODO Return difference between two Resources object
continue
}
currentState.Desired[k] = v
}
backend.WriteState(&currentState)

backend.WriteState(currentState)
}

func reapResources() {
// stoppableResources := provider.GetStoppableResources(allResources)
// fmt.Println("Stoppable Resources: ", stoppableResources)
// errs := provider.StopResources(stoppableResources)
// fmt.Println("Errors Stopping Resources: ", errs)

// resumableResources := provider.GetResumableResources(allResources)
// fmt.Println("Resumable Resources: ", resumableResources)
// errs = provider.ResumeResources(resumableResources)
// fmt.Println("Errors Resuming Resources: ", errs)

// destroyableResources := provider.GetDestroyableResources(allResources)
// fmt.Println("Destroyable Resources: ", destroyableResources)
// errs = provider.DestroyResources(destroyableResources)
// fmt.Println("Errors Destroying Resources: ", errs)
}
2 changes: 1 addition & 1 deletion provider/aws/ec2_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var ec2Manager resource.Manager

const (
// Name of resource
ec2Name = "EC2"
ec2Name = "ec2"
// LongName descriptive name for resource
ec2LongName = "Elastic Compute Cloud"
)
Expand Down
2 changes: 1 addition & 1 deletion provider/aws/eip_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var eipManager resource.Manager

const (
// Name of resource
eipName = "EIP"
eipName = "eip"
// LongName descriptive name for resource
eipLongName = "Elastic IP"
)
Expand Down
2 changes: 1 addition & 1 deletion provider/aws/eks_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var eksManager resource.Manager

const (
// Name of resource
eksName = "EKS"
eksName = "eks"
// LongName descriptive name for resource
eksLongName = "Elastic Compute Cloud"

Expand Down
2 changes: 1 addition & 1 deletion provider/aws/s3_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

const (
// Name of resource
s3Name = "S3"
s3Name = "s3"
// LongName descriptive name for resource
s3LongName = "Simple Storage Service"
)
Expand Down
6 changes: 4 additions & 2 deletions state/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Backender interface {

// Reader is the interface for state types that can return state resources
type Reader interface {
Get() *State
GetState() *State
}

// Writer is the interface for state types that can write to state files
Expand All @@ -31,8 +31,10 @@ func InitBackend() Backender {
switch cfg.StateBackend.Type {
default:
log.Debugf("using Local State at %s", cfg.StateBackend.Path)
s := NewEmptyState()
backend = LocalBackend{
Path: cfg.StateBackend.Path,
Path: cfg.StateBackend.Path,
state: &s,
}
}
return backend
Expand Down
8 changes: 4 additions & 4 deletions state/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ type LocalBackend struct {
Path string
}

// Get returns state from local source
func (s LocalBackend) Get() *State {
if s.state.empty() {
// GetState returns state from local source
func (s LocalBackend) GetState() *State {
if s.state.Empty() {
if _, err := os.Stat(s.Path); os.IsNotExist(err) {
s.state = &State{}
log.Debugf("State file not found, using empty state")
return s.state
}
stateFile, err := os.Open(s.Path)
Expand Down
44 changes: 36 additions & 8 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,49 @@ import (
var backend Backender
var cfg *config.Config

// State object: Represents a reka state consisting of resources
// aws: {
// ProvidersState represents state for providers
// {
// aws: {
// s3: [ Resource1, Resource2 ]
// }
// }
type ProvidersState map[string]provider.Resources

// State object: Represents a reka state consisting of current and desired state
// Desired state is used for resumption of resources. It stores the attributes of the resource to resume to
// for resources that need extra info like size of node pool to resize to
// current: {
// aws: {
// s3: [ Resource1, Resource2 ]
// }
// }
// desired: {
// aws: {
// s3: [ Resource1, Resource2 ]
// }
// }
type State map[string]provider.Resources
// State object stores state for both current and desired states
// of resources
type State struct {
Current ProvidersState
Desired ProvidersState
}

func (s *State) diff(st *State) State {
return Diff(s, st)
func (s *State) diff() State {
return Diff(s.Desired, s.Current)
}

func (s State) empty() bool {
return len(s) == 0
// Empty checks if state is empty
func (s State) Empty() bool {
return len(s.Current) == 0 && len(s.Desired) == 0
}

// Diff returns the difference in between two states
func Diff(previous, current *State) State {
func Diff(previous, current ProvidersState) State {
return State{}
}

// NewEmptyState gets a new empty state
func NewEmptyState() State {
return State{Desired: make(ProvidersState), Current: make(ProvidersState)}
}

0 comments on commit 9bcfd2a

Please sign in to comment.