Skip to content

Commit

Permalink
Merge pull request #250 from shalb/state-lock-fix
Browse files Browse the repository at this point in the history
fix bug with state locking after cdev error
  • Loading branch information
romanprog authored Mar 11, 2024
2 parents 2ad51c3 + 64b2ad0 commit 3e5bea8
Show file tree
Hide file tree
Showing 29 changed files with 235 additions and 148 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
tests:
name: Build and run tests
runs-on: ubuntu-latest
container: golang:1.20.2-alpine
container: golang:1.21.3-alpine
steps:

- name: Install soft
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
name: Release bin version
runs-on: ubuntu-latest
# if: github.event_name != 'workflow_dispatch'
container: golang:1.20.2-alpine
container: golang:1.21.3-alpine
steps:

- name: Install make
Expand Down
78 changes: 40 additions & 38 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
module github.com/shalb/cluster.dev

go 1.20
go 1.21

toolchain go1.21.3

require (
cloud.google.com/go/storage v1.33.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
github.com/Azure/azure-storage-blob-go v0.15.0
github.com/Masterminds/semver v1.5.0
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/apex/log v1.9.0
github.com/apparentlymart/go-cidr v1.1.0
github.com/aws/aws-sdk-go v1.46.1
github.com/aws/aws-sdk-go-v2 v1.21.2
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13
github.com/aws/aws-sdk-go-v2/service/s3 v1.40.2
github.com/aws/aws-sdk-go-v2 v1.25.0
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.50.2
github.com/getsops/sops/v3 v3.8.1
github.com/gookit/color v1.5.4
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.37
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.48
github.com/hashicorp/hcl/v2 v2.19.1
github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0
github.com/iancoleman/strcase v0.3.0
Expand All @@ -28,7 +29,7 @@ require (
github.com/spf13/cobra v1.7.0
github.com/tj/go-spin v1.1.0
github.com/zclconf/go-cty v1.14.1
golang.org/x/crypto v0.14.0
golang.org/x/crypto v0.21.0
golang.org/x/oauth2 v0.13.0
google.golang.org/api v0.148.0
gopkg.in/yaml.v3 v3.0.1
Expand All @@ -37,10 +38,11 @@ require (
)

require (
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/google/go-github v17.0.0+incompatible // indirect
github.com/google/go-github/v60 v60.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
)

require (
Expand All @@ -61,31 +63,31 @@ require (
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.44 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.42 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.44 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.6 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.22.1 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.22.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.38 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.36 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.6 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.0 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.29.1 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.30.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.0 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.24.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.24.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.15.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.23.1 // indirect
github.com/aws/smithy-go v1.15.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.30.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.19.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.22.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.27.1 // indirect
github.com/aws/smithy-go v1.20.0 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/buger/goterm v1.0.4 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/cloudflare/circl v1.3.5 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
Expand All @@ -95,7 +97,7 @@ require (
github.com/fatih/color v1.15.0 // indirect
github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
Expand Down Expand Up @@ -183,18 +185,18 @@ require (
github.com/xlab/treeprint v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.45.0 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/otel/metric v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.48.0 // indirect
go.opentelemetry.io/otel v1.23.1 // indirect
go.opentelemetry.io/otel/metric v1.23.1 // indirect
go.opentelemetry.io/otel/trace v1.23.1 // indirect
go.starlark.net v0.0.0-20231016134836-22325403fcb3 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sync v0.4.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
Expand Down
2 changes: 0 additions & 2 deletions pkg/cmd/cdev/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ var destroyCmd = &cobra.Command{
}
err = project.Destroy()
if err != nil {
project.UnLockState()
return NewCmdErr(project, "destroy", err)
}
log.Info("The project was successfully destroyed")
project.UnLockState()
return NewCmdErr(project, "destroy", nil)
},
}
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/cdev/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func init() {

func Run() {
profiler.Global.MainTimeLine().Start()

err := rootCmd.Execute()
extendedErr, ok := err.(*CmdErrExtended)
if !ok {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/cdev/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ var outputCmd = &cobra.Command{
log.Fatalf("Fatal error: outputs: %v", err.Error())
}
err = project.LockState()
defer project.UnLockState()
if err != nil {
log.Fatalf("Fatal error: outputs: lock state: %v", err.Error())
}
err = project.OwnState.PrintOutputs()
if err != nil {
log.Fatalf("Fatal error: outputs: print %v", err.Error())
}
project.UnLockState()
},
}

Expand Down
55 changes: 49 additions & 6 deletions pkg/project/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package project

import (
"fmt"
"os"
"os/signal"
"syscall"

"github.com/apex/log"
"github.com/paulrademacher/climenu"
Expand Down Expand Up @@ -38,8 +41,14 @@ func (p *Project) Destroy() error {
return nil
}
if !config.Global.Force {
stopChan := make(chan struct{})
p.StartSigTrap(stopChan)
showPlanResults(destroyGraph)
if p.NewVersionMessage != "" {
log.Info(p.NewVersionMessage)
}
respond := climenu.GetText("Continue?(yes/no)", "no")
stopChan <- struct{}{}
if respond != "yes" {
log.Info("Destroying cancelled")
return nil
Expand Down Expand Up @@ -87,6 +96,31 @@ func (p *Project) Destroy() error {
}
}

func (p *Project) StartSigTrap(stop chan struct{}) {
p.HupUnlockChan = make(chan os.Signal, 1)
signals := []os.Signal{syscall.SIGTERM, syscall.SIGINT}
signal.Notify(p.HupUnlockChan, signals...)
go func() {
for {
select {
case <-p.HupUnlockChan:
fmt.Println()
log.Warnf("Execution halted. Unlocking state and exiting...")
p.UnLockState()
close(p.HupUnlockChan)
os.Exit(0)
case <-stop:
close(p.HupUnlockChan)
return
}
}
}()
}

func (p *Project) StopSigTrap() {
close(p.HupUnlockChan)
}

// Apply all units.
func (p *Project) Apply() error {
// var applyGraph *ProjectPlanningStatus
Expand All @@ -98,7 +132,13 @@ func (p *Project) Apply() error {
if !applyGraph.planningUnits.HasChanges() {
return nil
}
if p.NewVersionMessage != "" {
log.Info(p.NewVersionMessage)
}
stopChan := make(chan struct{})
p.StartSigTrap(stopChan)
respond := climenu.GetText("Continue?(yes/no)", "no")
stopChan <- struct{}{}
if respond != "yes" {
log.Info("Cancelled")
return nil
Expand All @@ -113,7 +153,7 @@ func (p *Project) Apply() error {
for {
// log.Warnf("FOR Project apply. Unit links: %+v", p.UnitLinks)
if applyGraph.Len() == 0 {
return p.SaveState()
return p.OwnState.SaveState()
}
gUnit, fn, err := applyGraph.GetNextAsync()
if err != nil {
Expand All @@ -126,15 +166,15 @@ func (p *Project) Apply() error {
for _, e := range applyGraph.Errors() {
log.Errorf("unit: '%v':\n%v", e.Key(), e.ExecError())
}
err := p.SaveState()
err := p.OwnState.SaveState()
if err != nil {
return fmt.Errorf("save state after error: %w", err)
}
return fmt.Errorf("applying error")
}
// Check if graph return nil unit - applying finished, return
if gUnit == nil {
p.SaveState()
p.OwnState.SaveState()
return nil
}
switch gUnit.Operation {
Expand All @@ -153,17 +193,20 @@ func applyRoutine(graphUnit *UnitPlanningStatus, finFunc func(error), p *Project
log.Infof(colors.Fmt(colors.LightWhiteBold).Sprintf("Applying unit '%v':", graphUnit.UnitPtr.Key()))
err := graphUnit.UnitPtr.Build()
if err != nil {
log.Errorf("project apply: unit build error: %v", err.Error())
log.Errorf("unit build error: %v", err.Error())
finFunc(err)
return
}
p.ProcessedUnitsCount++
err = graphUnit.UnitPtr.Apply()
if err != nil {
state, _ := utils.JSONEncode(graphUnit.UnitPtr)
log.Warnf("applyRoutine: %v", string(state))
if graphUnit.UnitPtr.IsTainted() {
// log.Warnf("applyRoutine: tainted %v", graphUnit.UnitPtr.Key())
p.OwnState.UpdateUnit(graphUnit.UnitPtr)
}
finFunc(fmt.Errorf("project apply: destroying deleted unit: %v", err.Error()))
finFunc(fmt.Errorf("apply unit: %v", err.Error()))
return
}
err = graphUnit.UnitPtr.UpdateProjectRuntimeData(p)
Expand All @@ -188,7 +231,7 @@ func destroyRoutine(graphUnit *UnitPlanningStatus, finFunc func(error), p *Proje
p.ProcessedUnitsCount++
err = graphUnit.UnitPtr.Destroy()
if err != nil {
finFunc(fmt.Errorf("project apply: destroying deleted unit: %v", err.Error()))
finFunc(fmt.Errorf("destroy unit: %v", err.Error()))
return
}
p.OwnState.DeleteUnit(graphUnit.UnitPtr)
Expand Down
9 changes: 9 additions & 0 deletions pkg/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ type Project struct {
OwnState *StateProject
UUID string
ProcessedUnitsCount uint
HupUnlockChan chan os.Signal
NewVersionMessage string
}

// NewEmptyProject creates new empty project. The configuration will not be loaded.
func NewEmptyProject() *Project {

project := &Project{
SessionId: utils.Md5(utils.RandString(64)),
Stacks: make(map[string]*Stack),
Expand All @@ -73,6 +76,12 @@ func NewEmptyProject() *Project {
},
CodeCacheDir: config.Global.CacheDir,
}
log.Info("Checking for newer releases...")
err := utils.DiscoverCdevLastRelease()
if err != nil {
log.Warnf("Version check: %v.", err)
project.NewVersionMessage = fmt.Sprintf("Version check: %v", err.Error())
}
return project
}

Expand Down
12 changes: 10 additions & 2 deletions pkg/project/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import (
)

func (sp *StateProject) UpdateUnit(unit Unit) {
// log.Warnf("UpdateUnit %v", unit.Key())
// for u, _ := range sp.Units {
// log.Warnf(" %v", u)
// }
sp.StateMutex.Lock()
defer sp.StateMutex.Unlock()
sp.Units[unit.Key()] = unit
Expand Down Expand Up @@ -52,8 +56,9 @@ func (p *Project) SaveState() error {
Units: map[string]interface{}{},
}
// log.Errorf("units links: %+v\n Project: %+v", st.UnitLinks, p.UnitLinks)
for key, mod := range p.Units {
st.Units[key] = mod.GetState()
for key, unit := range p.Units {
log.Warnf("SaveState %v", key)
st.Units[key] = unit.GetState()
}
// Remove all unit links, that not have a target unit.
st.ClearULinks()
Expand Down Expand Up @@ -232,6 +237,9 @@ func (p *Project) LoadState() (*StateProject, error) {
if err != nil {
return nil, err
}
for key, _ := range statePrj.Units {
log.Warnf("LoadState %v", key)
}

return statePrj, nil
}
Expand Down
Loading

0 comments on commit 3e5bea8

Please sign in to comment.