diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index a1ef5d53..324183ed 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -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 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bf4b79df..1a89aceb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -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 diff --git a/go.mod b/go.mod index 56796598..af7d7c24 100644 --- a/go.mod +++ b/go.mod @@ -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 @@ -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 @@ -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 ( @@ -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 @@ -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 @@ -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 diff --git a/pkg/cmd/cdev/destroy.go b/pkg/cmd/cdev/destroy.go index b8abe55c..6859fc71 100644 --- a/pkg/cmd/cdev/destroy.go +++ b/pkg/cmd/cdev/destroy.go @@ -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) }, } diff --git a/pkg/cmd/cdev/main.go b/pkg/cmd/cdev/main.go index d8f23d43..c2a78a31 100644 --- a/pkg/cmd/cdev/main.go +++ b/pkg/cmd/cdev/main.go @@ -31,6 +31,7 @@ func init() { func Run() { profiler.Global.MainTimeLine().Start() + err := rootCmd.Execute() extendedErr, ok := err.(*CmdErrExtended) if !ok { diff --git a/pkg/cmd/cdev/output.go b/pkg/cmd/cdev/output.go index bab66878..acb9262b 100644 --- a/pkg/cmd/cdev/output.go +++ b/pkg/cmd/cdev/output.go @@ -17,6 +17,7 @@ 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()) } @@ -24,7 +25,6 @@ var outputCmd = &cobra.Command{ if err != nil { log.Fatalf("Fatal error: outputs: print %v", err.Error()) } - project.UnLockState() }, } diff --git a/pkg/project/commands.go b/pkg/project/commands.go index 017eaeab..4c3c3033 100644 --- a/pkg/project/commands.go +++ b/pkg/project/commands.go @@ -2,6 +2,9 @@ package project import ( "fmt" + "os" + "os/signal" + "syscall" "github.com/apex/log" "github.com/paulrademacher/climenu" @@ -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 @@ -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 @@ -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 @@ -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 { @@ -126,7 +166,7 @@ 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) } @@ -134,7 +174,7 @@ func (p *Project) Apply() error { } // Check if graph return nil unit - applying finished, return if gUnit == nil { - p.SaveState() + p.OwnState.SaveState() return nil } switch gUnit.Operation { @@ -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) @@ -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) diff --git a/pkg/project/project.go b/pkg/project/project.go index 7bfb2c17..87029ca2 100644 --- a/pkg/project/project.go +++ b/pkg/project/project.go @@ -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), @@ -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 } diff --git a/pkg/project/state.go b/pkg/project/state.go index 5e30726d..749cd348 100644 --- a/pkg/project/state.go +++ b/pkg/project/state.go @@ -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 @@ -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() @@ -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 } diff --git a/pkg/project/unit.go b/pkg/project/unit.go index bb0bab40..aff94be8 100644 --- a/pkg/project/unit.go +++ b/pkg/project/unit.go @@ -21,7 +21,7 @@ type Unit interface { Plan() error Destroy() error Key() string - GetState() interface{} + GetState() Unit GetDiffData() interface{} GetStateDiffData() interface{} LoadState(interface{}, string, *StateProject) error @@ -32,7 +32,7 @@ type Unit interface { ForceApply() bool Mux() *sync.Mutex IsTainted() bool - SetTainted(newValue bool) + SetTainted(newValue bool, err error) SetExecStatus(ExecutionStatus) GetExecStatus() ExecutionStatus ExecError() error @@ -101,14 +101,14 @@ func NewUnitFromState(state map[string]interface{}, name string, p *StateProject return nil, fmt.Errorf("internal error: bad unit type in state '%v'", mType) } } - // stateUnit, err := modDrv.NewFromState(state, name, p) - // if err != nil { - // return nil, err - // } - // curUnit := p.LoaderProjectPtr.Units[stateUnit.Key()] - // if curUnit != nil { - // curUnit.SetTainted() - // } + // stateUnit, err := modDrv.NewFromState(state, name, p) + // if err != nil { + // return nil, err + // } + // curUnit := p.LoaderProjectPtr.Units[stateUnit.Key()] + // if curUnit != nil { + // curUnit.SetTainted() + // } return modDrv.NewFromState(state, name, p) } diff --git a/pkg/units/shell/common/state.go b/pkg/units/shell/common/state.go index 92a1c1f5..bcd5da28 100644 --- a/pkg/units/shell/common/state.go +++ b/pkg/units/shell/common/state.go @@ -31,7 +31,7 @@ func (u *Unit) GetStateUnit() *Unit { return &unitState } -func (u *Unit) GetState() interface{} { +func (u *Unit) GetState() project.Unit { if u.SavedState != nil { return u.SavedState } diff --git a/pkg/units/shell/common/unit.go b/pkg/units/shell/common/unit.go index d3975bee..b090216b 100644 --- a/pkg/units/shell/common/unit.go +++ b/pkg/units/shell/common/unit.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "path/filepath" - "reflect" "strings" "sync" @@ -69,7 +68,7 @@ type Unit struct { UnitKind string `yaml:"type" json:"type"` BackendPtr *project.Backend `yaml:"-" json:"-"` BackendName string `yaml:"-" json:"backend_name"` - SavedState interface{} `yaml:"-" json:"-"` + SavedState project.Unit `yaml:"-" json:"-"` DependsOn interface{} `yaml:"depends_on,omitempty" json:"depends_on,omitempty"` FApply bool `yaml:"force_apply" json:"force_apply"` lockedMux *sync.Mutex `yaml:"-" json:"-"` @@ -79,8 +78,14 @@ type Unit struct { } // IsTainted return true if unit have tainted state (failed previous apply or destroy). -func (u *Unit) SetTainted(newValue bool) { +func (u *Unit) SetTainted(newValue bool, err error) { u.Tainted = newValue + u.ExecErr = err + log.Warnf("SetTainted %v", u.Key()) + if u.SavedState != nil { + log.Warnf("SetTainted %v", u.SavedState.Key()) + u.SavedState.SetTainted(newValue, err) + } } // IsTainted return true if unit have tainted state (failed previous apply or destroy). @@ -282,8 +287,10 @@ func (u *Unit) Apply() error { applyCommands.Commands = append(applyCommands.Commands, "./post_hook.sh") } u.OutputRaw, err = u.runCommands(applyCommands, "apply") + // unitIsTainted := err != nil + if err != nil { - u.MarkTainted(err) + u.SetTainted(true, err) return fmt.Errorf("apply unit '%v': %w", u.Key(), err) } // Get outputs. @@ -295,14 +302,14 @@ func (u *Unit) Apply() error { } u.OutputRaw, err = u.runCommands(cmdConf, "retrieving outputs") if err != nil { - u.MarkTainted(err) + u.SetTainted(true, err) return fmt.Errorf("retrieving unit '%v' outputs: %w", u.Key(), err) } } if u.GetOutputsConf != nil { parser, exists := u.OutputParsers[u.GetOutputsConf.Type] if !exists { - u.MarkTainted(err) + u.SetTainted(true, err) return fmt.Errorf("retrieving unit '%v' outputs: parser %v doesn't exists", u.Key(), u.GetOutputsConf.Type) } err = parser(string(u.OutputRaw), u.ProjectPtr.UnitLinks.ByTargetUnit(u).ByLinkTypes(project.OutputLinkType)) @@ -310,7 +317,7 @@ func (u *Unit) Apply() error { //str := fmt.Sprintf("Outputs data: %s", string(u.OutputRaw)) // log.Warnf("Len: %v", len(str)) - u.MarkTainted(err) + u.SetTainted(true, err) return fmt.Errorf("parse outputs '%v': %w", u.GetOutputsConf.Type, err) } @@ -321,13 +328,13 @@ func (u *Unit) Apply() error { return err } -func (u *Unit) MarkTainted(err error) { - u.ExecErr = err - if u.SavedState != nil { - rf := reflect.ValueOf(u.SavedState).Interface().(project.Unit) - rf.SetTainted(true) - } -} +// func (u *Unit) MarkTainted(err error) { +// u.ExecErr = err +// if u.SavedState != nil { +// u.SavedState.SetTainted(true) +// log.Warnf("MarkTainted %v", u.SavedState.IsTainted()) +// } +// } func (u *Unit) runCommands(commandsCnf OperationConfig, name string) ([]byte, error) { if len(commandsCnf.Commands) == 0 { @@ -361,7 +368,7 @@ func (u *Unit) runCommands(commandsCnf OperationConfig, name string) ([]byte, er } otp, errMsg, err := rn.Run(cmd) if err != nil { - log.Errorf("%v", string(errMsg)) + // log.Errorf("%v", string(errMsg)) return otp, fmt.Errorf("%w, error output:\n %v", err, string(errMsg)) } return otp, err @@ -409,7 +416,7 @@ func (u *Unit) Destroy() error { } _, err = u.runCommands(destroyCommands, "destroy") if err != nil { - u.MarkTainted(err) + u.SetTainted(true, err) } else { u.AlreadyDestroyed = true } diff --git a/pkg/units/shell/k8s_manifest/state.go b/pkg/units/shell/k8s_manifest/state.go index f93a33c0..6ec14d25 100644 --- a/pkg/units/shell/k8s_manifest/state.go +++ b/pkg/units/shell/k8s_manifest/state.go @@ -3,6 +3,8 @@ package base import ( "fmt" + "github.com/apex/log" + "github.com/shalb/cluster.dev/pkg/project" "github.com/shalb/cluster.dev/pkg/units/shell/common" "github.com/shalb/cluster.dev/pkg/utils" @@ -13,14 +15,15 @@ type UnitDiffSpec struct { Manifests interface{} `json:"manifests"` } -func (u *Unit) GetState() interface{} { +func (u *Unit) GetState() project.Unit { if u.SavedState != nil { return u.SavedState } unitState := Unit{} err := utils.JSONCopy(u, &unitState) if err != nil { - return fmt.Errorf("read unit '%v': create state: %w", u.Name(), err) + log.Fatalf("read unit '%v': create state: %w", u.Name(), err) + // return nil } unitState.Unit = *u.Unit.GetStateUnit() unitState.ApplyConf = nil diff --git a/pkg/units/shell/k8s_manifest/unit.go b/pkg/units/shell/k8s_manifest/unit.go index e57bfdab..b6b2aba1 100644 --- a/pkg/units/shell/k8s_manifest/unit.go +++ b/pkg/units/shell/k8s_manifest/unit.go @@ -35,7 +35,6 @@ type Unit struct { ApplyTemplate bool `yaml:"apply_template" json:"-"` recursive bool `yaml:"-" json:"-"` UnitKind string `yaml:"-" json:"type"` - SavedState interface{} `yaml:"-" json:"-"` manifestsForDelete *common.FilesListT `yaml:"-" json:"-"` CreateNamespaces bool `yaml:"create_namespaces" json:"-"` createNSList []string `yaml:"-" json:"-"` diff --git a/pkg/units/shell/terraform/base/state.go b/pkg/units/shell/terraform/base/state.go index 4088e708..58a3e305 100644 --- a/pkg/units/shell/terraform/base/state.go +++ b/pkg/units/shell/terraform/base/state.go @@ -38,12 +38,12 @@ func (u *Unit) GetStateUnit() *Unit { return &unitState } -func (u *Unit) GetState() interface{} { +func (u *Unit) GetState() project.Unit { - if u.StateData != nil { - return u.StateData + if u.SavedState != nil { + return u.SavedState } - return *u.GetStateUnit() + return u.GetStateUnit() } func (u *Unit) GetUnitDiff() UnitDiffSpec { diff --git a/pkg/units/shell/terraform/base/unit.go b/pkg/units/shell/terraform/base/unit.go index 5198f9d2..5ad85710 100644 --- a/pkg/units/shell/terraform/base/unit.go +++ b/pkg/units/shell/terraform/base/unit.go @@ -31,7 +31,8 @@ type Unit struct { Providers interface{} `yaml:"-" json:"providers,omitempty"` RequiredProviders map[string]RequiredProvider `yaml:"-" json:"required_providers,omitempty"` InitDone bool `yaml:"-" json:"-"` // True if unit was initted in this session. - StateData interface{} `yaml:"-" json:"-"` + // StateData project.Unit `yaml:"-" json:"-"` + // SavedState string } func (u *Unit) AddRequiredProvider(name, source, version string) { diff --git a/pkg/units/shell/terraform/helm/main.go b/pkg/units/shell/terraform/helm/main.go index 657f8a64..81d98666 100644 --- a/pkg/units/shell/terraform/helm/main.go +++ b/pkg/units/shell/terraform/helm/main.go @@ -28,7 +28,7 @@ type Unit struct { ValuesFilesList []string `yaml:"-" json:"values,omitempty"` ValuesYAML []map[string]interface{} `yaml:"-" json:"-"` UnitKind string `yaml:"-" json:"type"` - StateData interface{} `yaml:"-" json:"-"` + StateData project.Unit `yaml:"-" json:"-"` CustomFiles *common.FilesListT `yaml:"create_files,omitempty" json:"create_files,omitempty"` } diff --git a/pkg/units/shell/terraform/helm/state.go b/pkg/units/shell/terraform/helm/state.go index 17e31dae..f33c028d 100644 --- a/pkg/units/shell/terraform/helm/state.go +++ b/pkg/units/shell/terraform/helm/state.go @@ -21,11 +21,11 @@ func (u *Unit) GetStateUnit() *Unit { return &unitState } -func (u *Unit) GetState() interface{} { +func (u *Unit) GetState() project.Unit { if u.StateData != nil { return u.StateData } - return *u.GetStateUnit() + return u.GetStateUnit() } type UnitDiffSpec struct { diff --git a/pkg/units/shell/terraform/kubernetes/main.go b/pkg/units/shell/terraform/kubernetes/main.go index 3f709879..2fd40bbf 100644 --- a/pkg/units/shell/terraform/kubernetes/main.go +++ b/pkg/units/shell/terraform/kubernetes/main.go @@ -24,7 +24,7 @@ type Unit struct { // providerVersion string `yaml:"-" json:"-"` ProviderConf ProviderConfigSpec `yaml:"-" json:"provider_conf"` UnitKind string `yaml:"-" json:"type"` - StateData interface{} `yaml:"-" json:"-"` + StateData project.Unit `yaml:"-" json:"-"` } type ExecNestedSchema struct { diff --git a/pkg/units/shell/terraform/kubernetes/state.go b/pkg/units/shell/terraform/kubernetes/state.go index cb0e4cbc..f7d326a3 100644 --- a/pkg/units/shell/terraform/kubernetes/state.go +++ b/pkg/units/shell/terraform/kubernetes/state.go @@ -20,11 +20,11 @@ func (u *Unit) GetStateUnit() *Unit { return &unitState } -func (u *Unit) GetState() interface{} { +func (u *Unit) GetState() project.Unit { if u.StateData != nil { return u.StateData } - return *u.GetStateUnit() + return u.GetStateUnit() } type UnitDiffSpec struct { diff --git a/pkg/units/shell/terraform/module/main.go b/pkg/units/shell/terraform/module/main.go index 69ae9aeb..0e325ab8 100644 --- a/pkg/units/shell/terraform/module/main.go +++ b/pkg/units/shell/terraform/module/main.go @@ -20,14 +20,14 @@ import ( type Unit struct { base.Unit - Source string `yaml:"-" json:"source"` - Version string `yaml:"-" json:"version,omitempty"` - Inputs map[string]interface{} `yaml:"-" json:"inputs,omitempty"` - LocalModule *common.FilesListT `yaml:"-" json:"local_module"` - CustomFiles *common.FilesListT `yaml:"create_files,omitempty" json:"create_files,omitempty"` - UnitKind string `yaml:"-" json:"type"` - StateData interface{} `yaml:"-" json:"-"` - LocalModuleCachePath string `yaml:"-" json:"-"` + Source string `yaml:"-" json:"source"` + Version string `yaml:"-" json:"version,omitempty"` + Inputs map[string]interface{} `yaml:"-" json:"inputs,omitempty"` + LocalModule *common.FilesListT `yaml:"-" json:"local_module"` + CustomFiles *common.FilesListT `yaml:"create_files,omitempty" json:"create_files,omitempty"` + UnitKind string `yaml:"-" json:"type"` + // StateData project.Unit `yaml:"-" json:"-"` + LocalModuleCachePath string `yaml:"-" json:"-"` } func (u *Unit) KindKey() string { diff --git a/pkg/units/shell/terraform/module/state.go b/pkg/units/shell/terraform/module/state.go index 4e0ae713..ee09cef9 100644 --- a/pkg/units/shell/terraform/module/state.go +++ b/pkg/units/shell/terraform/module/state.go @@ -30,11 +30,11 @@ func (u *Unit) GetStateUnit() *Unit { return &unitState } -func (u *Unit) GetState() interface{} { - if u.StateData != nil { - return u.StateData +func (u *Unit) GetState() project.Unit { + if u.SavedState != nil { + return u.SavedState } - return *u.GetStateUnit() + return u.GetStateUnit() } func (u *Unit) GetUnitDiff() UnitDiffSpec { diff --git a/pkg/units/shell/terraform/printer/main.go b/pkg/units/shell/terraform/printer/main.go index bb704278..2eb5db87 100644 --- a/pkg/units/shell/terraform/printer/main.go +++ b/pkg/units/shell/terraform/printer/main.go @@ -18,7 +18,7 @@ type Unit struct { InputsDeprecated map[string]interface{} `yaml:"-" json:"inputs,omitempty"` Outputs map[string]interface{} `yaml:"-" json:"outputs"` UnitKind string `yaml:"-" json:"type"` - StateData *Unit `yaml:"-" json:"-"` + // StateData *Unit `yaml:"-" json:"-"` } func (u *Unit) KindKey() string { @@ -75,6 +75,8 @@ func (u *Unit) ReadConfig(spec map[string]interface{}, stack *project.Stack) err switch stateOutput := myStateIntf.(type) { case *Unit: u.OutputRaw = stateOutput.OutputRaw + default: + log.Fatalf("Internal error. Type mismatch") } } return nil @@ -105,7 +107,7 @@ func (u *Unit) Prepare() error { // Build generate all terraform code for project. func (u *Unit) Build() error { // Save state before outputs replacing. - u.StateData = u.GetStateUnit() + u.SavedState = u.GetStateUnit() // Replace outputs. err := u.ScanData(project.OutputsReplacer) if err != nil { @@ -126,11 +128,11 @@ func (u *Unit) Build() error { func (u *Unit) Destroy() (err error) { err = u.Unit.Destroy() - if u.IsTainted() { - if u.SavedState != nil { - u.StateData.MarkTainted(err) - } - } + // if u.IsTainted() { + // if u.SavedState != nil { + // u.SavedState.SetTainted(true, err) + // } + // } if err != nil { return } @@ -140,11 +142,11 @@ func (u *Unit) Destroy() (err error) { func (u *Unit) Apply() (err error) { err = u.Unit.Apply() - if u.IsTainted() { - if u.SavedState != nil { - u.StateData.MarkTainted(err) - } - } + // if u.IsTainted() { + // if u.SavedState != nil { + // u.SavedState.SetTainted(true) + // } + // } if err != nil { return } @@ -153,7 +155,7 @@ func (u *Unit) Apply() (err error) { return } u.OutputRaw = outputs - u.StateData.OutputRaw = outputs + u.SavedState.(*Unit).OutputRaw = outputs // log.Warnf("Printer OutputRaw: %v", outputs) return } diff --git a/pkg/units/shell/terraform/printer/state.go b/pkg/units/shell/terraform/printer/state.go index d37c4a8c..293f7605 100644 --- a/pkg/units/shell/terraform/printer/state.go +++ b/pkg/units/shell/terraform/printer/state.go @@ -21,11 +21,11 @@ func (u *Unit) GetStateUnit() *Unit { return &unitState } -func (u *Unit) GetState() interface{} { - if u.StateData != nil { - return u.StateData +func (u *Unit) GetState() project.Unit { + if u.SavedState != nil { + return u.SavedState } - return *u.GetStateUnit() + return u.GetStateUnit() } type UnitDiffSpec struct { diff --git a/pkg/utils/git.go b/pkg/utils/git.go index e3d8a507..94c49297 100644 --- a/pkg/utils/git.go +++ b/pkg/utils/git.go @@ -1,11 +1,15 @@ package utils import ( + "context" "fmt" "path/filepath" "strings" + "github.com/Masterminds/semver" "github.com/apex/log" + "github.com/google/go-github/v60/github" + "github.com/shalb/cluster.dev/pkg/config" "github.com/shalb/cluster.dev/pkg/executor" ) @@ -79,3 +83,31 @@ func ParseGitUrl(gitURL string) (repo GitRepo, err error) { // log.Warnf("ParseGitUrl %+v", repo) return } + +func DiscoverCdevLastRelease() error { + var ( + client = github.NewClient(nil) + ctx = context.Background() + org string = "shalb" + project string = "cluster.dev" + ) + + latestRelease, _, err := client.Repositories.GetLatestRelease(ctx, org, project) + if err != nil { + return err + } + config.Version = "v0.9.0" + curVersion, err := semver.NewVersion(config.Version) + if err != nil { + return fmt.Errorf("check failed: %v, current version: %v", err, config.Global.Version) + } + reqVerConstraints, err := semver.NewConstraint(*latestRelease.TagName) + if err != nil { + return fmt.Errorf("check failed: %v, latest stable release: %v", err, *latestRelease.TagName) + } + ok, _ := reqVerConstraints.Validate(curVersion) + if !ok { + return fmt.Errorf("the new cdev version is available. Current version: '%v', latest stable release: '%v'. Visit https://docs.cluster.dev/installation-upgrade/ to upgrade", curVersion, *latestRelease.TagName) + } + return nil +} diff --git a/tests/test-project/graph-test/template.yaml b/tests/test-project/graph-test/template.yaml index 7b90befb..878a0449 100644 --- a/tests/test-project/graph-test/template.yaml +++ b/tests/test-project/graph-test/template.yaml @@ -8,7 +8,7 @@ units: apply: commands: - echo "Waiting..." - - sleep 5 + - sleep 1 - name: force_apply_unit type: shell @@ -17,21 +17,21 @@ units: apply: commands: - echo "Waiting..." - - sleep 4 + - sleep 2 - name: parallelWatcher1 type: shell apply: commands: - echo "Waiting..." - - sleep 8 + - sleep 3 - name: parallelWatcher2 type: shell apply: commands: - echo "Waiting..." - - sleep 5 + - sleep 2 - name: parallelWatcher3 type: shell @@ -39,7 +39,7 @@ units: apply: commands: - echo "Waiting..." - - sleep 2 + - sleep 1 - name: parallelWatcher4 type: shell @@ -55,7 +55,7 @@ units: apply: commands: - echo "Waiting..." - - sleep 10 + - sleep 1 - name: parallelWatcher5 type: shell @@ -63,7 +63,7 @@ units: apply: commands: - echo "Waiting..." - - sleep 7 + - sleep 3 - name: parallelWatcher6 type: shell @@ -71,7 +71,7 @@ units: apply: commands: - echo "Waiting..." - - sleep 10 + - sleep 1 - exit 0 - name: firstUnit diff --git a/tests/test-project/local-tmpl/s3-file/main.tf b/tests/test-project/local-tmpl/s3-file/main.tf index 8f5c2382..e6536b36 100644 --- a/tests/test-project/local-tmpl/s3-file/main.tf +++ b/tests/test-project/local-tmpl/s3-file/main.tf @@ -14,4 +14,4 @@ resource "aws_s3_bucket_object" "cdev_object" { output "cantent" { value = var.data -} \ No newline at end of file +} diff --git a/tests/test-project/s3-file/main.tf b/tests/test-project/s3-file/main.tf deleted file mode 100755 index aeeb93e1..00000000 --- a/tests/test-project/s3-file/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -variable "data" { - type = string -} -variable "bucket_name" { - type = string -} -resource "aws_s3_bucket_object" "cdev_object" { - key = "cdevs3data" - bucket = var.bucket_name - content = var.data - - force_destroy = true -} - -output "cantent" { - value = var.data -} diff --git a/tests/test-project/s3-file/s3file.txt b/tests/test-project/s3-file/s3file.txt deleted file mode 100755 index 34951880..00000000 --- a/tests/test-project/s3-file/s3file.txt +++ /dev/null @@ -1 +0,0 @@ -File will be uploaded to s3 bucket.