diff --git a/cmd/werf/bundle/apply/apply.go b/cmd/werf/bundle/apply/apply.go index 0c28c63a24..c00912abb2 100644 --- a/cmd/werf/bundle/apply/apply.go +++ b/cmd/werf/bundle/apply/apply.go @@ -214,9 +214,15 @@ func runApply() error { ChartExtender: bundle, } + stagesExternalDepsGenerator, err := helm.NewStagesExternalDepsGenerator(actionConfig.RESTClientGetter) + if err != nil { + return fmt.Errorf("error creating external deps generator: %w", err) + } + helmUpgradeCmd, _ := helm_v3.NewUpgradeCmd(actionConfig, logboek.Context(ctx).OutStream(), helm_v3.UpgradeCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, - ChainPostRenderer: bundle.ChainPostRenderer, + StagesSplitter: helm.NewStagesSplitter(), + StagesExternalDepsGenerator: stagesExternalDepsGenerator, + ChainPostRenderer: bundle.ChainPostRenderer, ValueOpts: &values.Options{ ValueFiles: common.GetValues(&commonCmdData), StringValues: common.GetSetString(&commonCmdData), diff --git a/cmd/werf/bundle/render/render.go b/cmd/werf/bundle/render/render.go index e2805f87f3..2f265b5197 100644 --- a/cmd/werf/bundle/render/render.go +++ b/cmd/werf/bundle/render/render.go @@ -221,7 +221,7 @@ func runRender(ctx context.Context) error { } helmTemplateCmd, _ := helm_v3.NewTemplateCmd(actionConfig, output, helm_v3.TemplateCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, + StagesSplitter: helm.NewStagesSplitter(), ChainPostRenderer: bundle.ChainPostRenderer, ValueOpts: &values.Options{ ValueFiles: common.GetValues(&commonCmdData), diff --git a/cmd/werf/converge/converge.go b/cmd/werf/converge/converge.go index 4fc2200acd..626ca947f9 100644 --- a/cmd/werf/converge/converge.go +++ b/cmd/werf/converge/converge.go @@ -444,15 +444,21 @@ func run(ctx context.Context, containerBackend container_backend.ContainerBacken return err } + stagesExternalDepsGenerator, err := helm.NewStagesExternalDepsGenerator(actionConfig.RESTClientGetter) + if err != nil { + return fmt.Errorf("error creating external deps generator: %w", err) + } + helmUpgradeCmd, _ := helm_v3.NewUpgradeCmd(actionConfig, logboek.OutStream(), helm_v3.UpgradeCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, - ChainPostRenderer: wc.ChainPostRenderer, - ValueOpts: valueOpts, - CreateNamespace: common.NewBool(true), - Install: common.NewBool(true), - Wait: common.NewBool(true), - Atomic: common.NewBool(cmdData.AutoRollback), - Timeout: common.NewDuration(time.Duration(cmdData.Timeout) * time.Second), + StagesSplitter: helm.NewStagesSplitter(), + StagesExternalDepsGenerator: stagesExternalDepsGenerator, + ChainPostRenderer: wc.ChainPostRenderer, + ValueOpts: valueOpts, + CreateNamespace: common.NewBool(true), + Install: common.NewBool(true), + Wait: common.NewBool(true), + Atomic: common.NewBool(cmdData.AutoRollback), + Timeout: common.NewDuration(time.Duration(cmdData.Timeout) * time.Second), }) return command_helpers.LockReleaseWrapper(ctx, releaseName, lockManager, func() error { @@ -525,7 +531,7 @@ func migrateHelm2ToHelm3(ctx context.Context, releaseName, namespace string, mai } helmTemplateCmd, _ := helm_v3.NewTemplateCmd(actionConfig, ioutil.Discard, helm_v3.TemplateCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, + StagesSplitter: helm.NewStagesSplitter(), ChainPostRenderer: chainPostRenderer, ValueOpts: valueOpts, Validate: common.NewBool(true), diff --git a/cmd/werf/dismiss/dismiss.go b/cmd/werf/dismiss/dismiss.go index b02a6e58e9..bee7a6c02d 100644 --- a/cmd/werf/dismiss/dismiss.go +++ b/cmd/werf/dismiss/dismiss.go @@ -232,7 +232,7 @@ func runDismiss(ctx context.Context) error { dontFailIfNoRelease := true helmUninstallCmd := helm_v3.NewUninstallCmd(actionConfig, logboek.Context(ctx).OutStream(), helm_v3.UninstallCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, + StagesSplitter: helm.NewStagesSplitter(), DeleteNamespace: &cmdData.WithNamespace, DeleteHooks: &cmdData.WithHooks, DontFailIfNoRelease: &dontFailIfNoRelease, diff --git a/cmd/werf/helm/helm.go b/cmd/werf/helm/helm.go index ebadc72378..f2dad6eec3 100644 --- a/cmd/werf/helm/helm.go +++ b/cmd/werf/helm/helm.go @@ -70,7 +70,7 @@ func NewCmd() *cobra.Command { cmd.AddCommand( helm_v3.NewUninstallCmd(actionConfig, os.Stdout, helm_v3.UninstallCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, + StagesSplitter: helm.NewStagesSplitter(), }), helm_v3.NewDependencyCmd(actionConfig, os.Stdout), helm_v3.NewGetCmd(actionConfig, os.Stdout), @@ -80,7 +80,9 @@ func NewCmd() *cobra.Command { NewTemplateCmd(actionConfig, wc), helm_v3.NewRepoCmd(os.Stdout), helm_v3.NewRollbackCmd(actionConfig, os.Stdout, helm_v3.RollbackCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, + StagesSplitter: helm.NewStagesSplitter(), + // TODO: actionConfig.RESTClientGetter not initialized at this point, but we need it. + StagesExternalDepsGenerator: nil, }), NewInstallCmd(actionConfig, wc), NewUpgradeCmd(actionConfig, wc), diff --git a/cmd/werf/helm/install.go b/cmd/werf/helm/install.go index e955ca2628..a64464a1d0 100644 --- a/cmd/werf/helm/install.go +++ b/cmd/werf/helm/install.go @@ -19,8 +19,10 @@ var installCmdData common.CmdData func NewInstallCmd(actionConfig *action.Configuration, wc *chart_extender.WerfChartStub) *cobra.Command { cmd, helmAction := helm_v3.NewInstallCmd(actionConfig, os.Stdout, helm_v3.InstallCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, - ChainPostRenderer: wc.ChainPostRenderer, + StagesSplitter: helm.NewStagesSplitter(), + // TODO: actionConfig.RESTClientGetter not initialized at this point, but we need it. + StagesExternalDepsGenerator: nil, + ChainPostRenderer: wc.ChainPostRenderer, }) SetupRenderRelatedWerfChartParams(cmd, &installCmdData) diff --git a/cmd/werf/helm/template.go b/cmd/werf/helm/template.go index d92f32f2d0..d384b93bb5 100644 --- a/cmd/werf/helm/template.go +++ b/cmd/werf/helm/template.go @@ -17,8 +17,10 @@ var templateCmdData common.CmdData func NewTemplateCmd(actionConfig *action.Configuration, wc *chart_extender.WerfChartStub) *cobra.Command { cmd, _ := helm_v3.NewTemplateCmd(actionConfig, os.Stdout, helm_v3.TemplateCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, - ChainPostRenderer: wc.ChainPostRenderer, + StagesSplitter: helm.NewStagesSplitter(), + // TODO: actionConfig.RESTClientGetter not initialized at this point, but we need it. + StagesExternalDepsGenerator: nil, + ChainPostRenderer: wc.ChainPostRenderer, }) SetupRenderRelatedWerfChartParams(cmd, &templateCmdData) diff --git a/cmd/werf/helm/upgrade.go b/cmd/werf/helm/upgrade.go index fc6b290115..68ca021988 100644 --- a/cmd/werf/helm/upgrade.go +++ b/cmd/werf/helm/upgrade.go @@ -19,8 +19,10 @@ var upgradeCmdData common.CmdData func NewUpgradeCmd(actionConfig *action.Configuration, wc *chart_extender.WerfChartStub) *cobra.Command { cmd, _ := helm_v3.NewUpgradeCmd(actionConfig, os.Stdout, helm_v3.UpgradeCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, - ChainPostRenderer: wc.ChainPostRenderer, + StagesSplitter: helm.NewStagesSplitter(), + // TODO: actionConfig.RESTClientGetter not initialized at this point, but we need it. + StagesExternalDepsGenerator: nil, + ChainPostRenderer: wc.ChainPostRenderer, }) SetupRenderRelatedWerfChartParams(cmd, &upgradeCmdData) diff --git a/cmd/werf/render/render.go b/cmd/werf/render/render.go index a00f024558..aab1d1fe0d 100644 --- a/cmd/werf/render/render.go +++ b/cmd/werf/render/render.go @@ -411,7 +411,7 @@ func runRender(ctx context.Context) error { } templateOpts := helm_v3.TemplateCmdOptions{ - StagesSplitter: helm.StagesSplitter{}, + StagesSplitter: helm.NewStagesSplitter(), ChainPostRenderer: wc.ChainPostRenderer, ValueOpts: &values.Options{ ValueFiles: common.GetValues(&commonCmdData), diff --git a/go.mod b/go.mod index 1c14bb43b7..d41653c53a 100644 --- a/go.mod +++ b/go.mod @@ -307,6 +307,6 @@ replace k8s.io/helm => github.com/werf/helm v0.0.0-20210202111118-81e74d46da0f replace github.com/deislabs/oras => github.com/werf/third-party-oras v0.9.1-0.20210927171747-6d045506f4c8 -replace helm.sh/helm/v3 => github.com/werf/3p-helm/v3 v3.0.0-20220615081302-d5ffa8d30462 +replace helm.sh/helm/v3 => github.com/werf/3p-helm/v3 v3.0.0-20220616090736-b002d47fddea replace github.com/go-git/go-git/v5 => github.com/ZauberNerd/go-git/v5 v5.4.3-0.20220315170230-29ec1bc1e5db diff --git a/go.sum b/go.sum index aeab22fb05..c0b462f6eb 100644 --- a/go.sum +++ b/go.sum @@ -2036,8 +2036,8 @@ github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59b github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/weppos/publicsuffix-go v0.5.0 h1:rutRtjBJViU/YjcI5d80t4JAVvDltS6bciJg2K1HrLU= github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= -github.com/werf/3p-helm/v3 v3.0.0-20220615081302-d5ffa8d30462 h1:u0njIasP6iKAiFKX7KJwz9/ufgYY+ph04wIWTHvqEPQ= -github.com/werf/3p-helm/v3 v3.0.0-20220615081302-d5ffa8d30462/go.mod h1:NxtE2KObf2PrzDl6SIamPFPKyAqWi10iWuvKlQn/Yao= +github.com/werf/3p-helm/v3 v3.0.0-20220616090736-b002d47fddea h1:qr9t42g4QEasedC84VS7NTltgeOG9OmXEXINckvZD1s= +github.com/werf/3p-helm/v3 v3.0.0-20220616090736-b002d47fddea/go.mod h1:NxtE2KObf2PrzDl6SIamPFPKyAqWi10iWuvKlQn/Yao= github.com/werf/copy-recurse v0.2.4 h1:kEyGUKhgS8WdEOjInNQKgk4lqPWzP2AgR27F3dcGsVc= github.com/werf/copy-recurse v0.2.4/go.mod h1:KVHSQ90p19xflWW0B7BJhLBwmSbEtuxIaBnjlUYRPhk= github.com/werf/helm v0.0.0-20210202111118-81e74d46da0f h1:81YscYTF9mmTf0ULOsCmm42YWQp+qWDzWi1HjWniZrg= diff --git a/pkg/deploy/helm/annotations.go b/pkg/deploy/helm/annotations.go index 6becab0636..18ce5a60b4 100644 --- a/pkg/deploy/helm/annotations.go +++ b/pkg/deploy/helm/annotations.go @@ -21,4 +21,7 @@ const ( ReplicasOnCreationAnnoName = "werf.io/replicas-on-creation" StageWeightAnnoName = "werf.io/weight" + + ExternalDependencyResourceAnnoName = "external-dependency.werf.io/resource" + ExternalDependencyNamespaceAnnoName = "external-dependency.werf.io/namespace" ) diff --git a/pkg/deploy/helm/external_deps_annotations_parser.go b/pkg/deploy/helm/external_deps_annotations_parser.go new file mode 100644 index 0000000000..76f0ac7f22 --- /dev/null +++ b/pkg/deploy/helm/external_deps_annotations_parser.go @@ -0,0 +1,160 @@ +package helm + +import ( + "fmt" + "strings" + + "github.com/werf/werf/pkg/slug" + "helm.sh/helm/v3/pkg/phases/stages/externaldeps" +) + +func NewExternalDepsAnnotationsParser() *ExternalDepsAnnotationsParser { + return &ExternalDepsAnnotationsParser{} +} + +type ExternalDepsAnnotationsParser struct{} + +func (s *ExternalDepsAnnotationsParser) Parse(annotations map[string]string) (externaldeps.ExternalDependencyList, error) { + extDeps, err := s.parseResourceAnnotations(annotations) + if err != nil { + return nil, fmt.Errorf("error parsing ext deps resource annotations: %w", err) + } + + extDeps, err = s.parseNamespaceAnnotations(extDeps, annotations) + if err != nil { + return nil, fmt.Errorf("error parsing ext deps namespace annotations: %w", err) + } + + return extDeps, nil +} + +func (s *ExternalDepsAnnotationsParser) parseResourceAnnotations(annotations map[string]string) (externaldeps.ExternalDependencyList, error) { + var externalDependencyList externaldeps.ExternalDependencyList + for annoKey, annoVal := range annotations { + annoKey, annoVal = s.normalizeAnnotation(annoKey, annoVal) + + if !s.matchResourceAnnotation(annoKey) { + continue + } + + if err := s.validateResourceAnnotation(annoKey, annoVal); err != nil { + return nil, fmt.Errorf("error validating external dependency resource annotation: %w", err) + } + + name := s.parseResourceAnnotationKey(annoKey) + resourceType, resourceName := s.parseResourceAnnotationValue(annoVal) + + externalDependencyList = append(externalDependencyList, externaldeps.NewExternalDependency(name, resourceType, resourceName)) + } + + return externalDependencyList, nil +} + +func (s *ExternalDepsAnnotationsParser) parseNamespaceAnnotations(extDeps externaldeps.ExternalDependencyList, annotations map[string]string) (externaldeps.ExternalDependencyList, error) { + for annoKey, annoVal := range annotations { + annoKey, annoVal = s.normalizeAnnotation(annoKey, annoVal) + + if !s.matchNamespaceAnnotation(annoKey) { + continue + } + + if err := s.validateNamespaceAnnotation(annoKey, annoVal); err != nil { + return nil, fmt.Errorf("error validating external dependency namespace annotation: %w", err) + } + + name := s.parseNamespaceAnnotationKey(annoKey) + + for _, extDep := range extDeps { + if extDep.Name == name { + extDep.Namespace = annoVal + break + } + } + } + + return extDeps, nil +} + +func (s *ExternalDepsAnnotationsParser) normalizeAnnotation(key, value string) (string, string) { + key = strings.TrimSpace(key) + key = strings.Trim(key, "/.") + key = strings.TrimSpace(key) + + value = strings.TrimSpace(value) + + return key, value +} + +func (s *ExternalDepsAnnotationsParser) matchResourceAnnotation(key string) bool { + return strings.HasSuffix(key, ExternalDependencyResourceAnnoName) +} + +func (s *ExternalDepsAnnotationsParser) matchNamespaceAnnotation(key string) bool { + return strings.HasSuffix(key, ExternalDependencyNamespaceAnnoName) +} + +func (s *ExternalDepsAnnotationsParser) validateResourceAnnotation(key, value string) error { + if key == ExternalDependencyResourceAnnoName { + return fmt.Errorf("annotation %q should have prefix specified, e.g. \"backend.%s\"", key, ExternalDependencyResourceAnnoName) + } + + if value == "" { + return fmt.Errorf("annotation %q value should be specified", key) + } + + valueElems := strings.Split(value, "/") + + if len(valueElems) != 2 { + return fmt.Errorf("wrong annotation %q value format, should be: type/name", key) + } + + switch valueElems[0] { + case "": + return fmt.Errorf("in annotation %q resource type can't be empty", key) + case "all": + return fmt.Errorf("\"all\" resource type is not allowed in annotation %q", key) + } + + resourceTypeParts := strings.Split(valueElems[0], ".") + for _, part := range resourceTypeParts { + if part == "" { + return fmt.Errorf("resource type in annotation %q should have dots (.) delimiting only non-empty resource.version.group: %s", ExternalDependencyResourceAnnoName, key) + } + } + + switch valueElems[1] { + case "": + return fmt.Errorf("in annotation %q resource name can't be empty", key) + } + + return nil +} + +func (s *ExternalDepsAnnotationsParser) validateNamespaceAnnotation(key, value string) error { + if key == ExternalDependencyNamespaceAnnoName { + return fmt.Errorf("annotation %q should have prefix specified, e.g. \"backend.%s\"", key, ExternalDependencyNamespaceAnnoName) + } + + if value == "" { + return fmt.Errorf("annotation %q value should be specified", key) + } + + if err := slug.ValidateKubernetesNamespace(value); err != nil { + return fmt.Errorf("error validating annotation \"%s=%s\" namespace name: %w", key, value, err) + } + + return nil +} + +func (s *ExternalDepsAnnotationsParser) parseResourceAnnotationKey(key string) (name string) { + return strings.TrimSuffix(key, fmt.Sprint(".", ExternalDependencyResourceAnnoName)) +} + +func (s *ExternalDepsAnnotationsParser) parseResourceAnnotationValue(value string) (resourceType, resourceName string) { + elems := strings.Split(value, "/") + return elems[0], elems[1] +} + +func (s *ExternalDepsAnnotationsParser) parseNamespaceAnnotationKey(key string) (name string) { + return strings.TrimSuffix(key, fmt.Sprint(".", ExternalDependencyNamespaceAnnoName)) +} diff --git a/pkg/deploy/helm/external_deps_generator.go b/pkg/deploy/helm/external_deps_generator.go new file mode 100644 index 0000000000..0dbb1a5c56 --- /dev/null +++ b/pkg/deploy/helm/external_deps_generator.go @@ -0,0 +1,87 @@ +package helm + +import ( + "fmt" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/phases/stages" + "helm.sh/helm/v3/pkg/phases/stages/externaldeps" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/restmapper" +) + +func NewStagesExternalDepsGenerator(restClient action.RESTClientGetter) (*StagesExternalDepsGenerator, error) { + mapper, err := restClient.ToRESTMapper() + if err != nil { + return nil, fmt.Errorf("error getting REST mapper: %w", err) + } + + discoveryClient, err := restClient.ToDiscoveryClient() + if err != nil { + return nil, fmt.Errorf("error getting discovery client: %w", err) + } + + gvkBuilder := NewGVKBuilder(scheme.Scheme, restmapper.NewShortcutExpander(mapper, discoveryClient)) + + return &StagesExternalDepsGenerator{ + metaAccessor: metadataAccessor, + scheme: scheme.Scheme, + gvkBuilder: gvkBuilder, + }, nil +} + +type StagesExternalDepsGenerator struct { + gvkBuilder externaldeps.GVKBuilder + metaAccessor meta.MetadataAccessor + scheme *runtime.Scheme +} + +func (s *StagesExternalDepsGenerator) Generate(stages stages.SortedStageList) error { + for _, stage := range stages { + if err := stage.DesiredResources.Visit(func(resInfo *resource.Info, err error) error { + if err != nil { + return err + } + + annotations, err := s.metaAccessor.Annotations(resInfo.Object) + if err != nil { + return fmt.Errorf("error getting annotations for object: %w", err) + } + + resExtDeps, err := s.resourceExternalDepsFromAnnotations(annotations) + if err != nil { + return fmt.Errorf("error generating external dependencies from resource annotations: %w", err) + } + + stage.ExternalDependencies = append(stage.ExternalDependencies, resExtDeps...) + + return nil + }); err != nil { + return fmt.Errorf("error visiting resources list: %w", err) + } + } + + return nil +} + +func (s *StagesExternalDepsGenerator) resourceExternalDepsFromAnnotations(annotations map[string]string) (externaldeps.ExternalDependencyList, error) { + extDepsList, err := NewExternalDepsAnnotationsParser().Parse(annotations) + if err != nil { + return nil, fmt.Errorf("error parsing external dependencies annotations: %w", err) + } + + if len(extDepsList) == 0 { + return nil, nil + } + + for _, extDep := range extDepsList { + if err := extDep.GenerateInfo(s.gvkBuilder, s.scheme, s.metaAccessor); err != nil { + return nil, fmt.Errorf("error generating Info for external dependency: %w", err) + } + } + + return extDepsList, nil +} diff --git a/pkg/deploy/helm/gvk_builder.go b/pkg/deploy/helm/gvk_builder.go new file mode 100644 index 0000000000..86e02e78ec --- /dev/null +++ b/pkg/deploy/helm/gvk_builder.go @@ -0,0 +1,73 @@ +package helm + +import ( + "fmt" + + "helm.sh/helm/v3/pkg/phases/stages/externaldeps" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "k8s.io/kubectl/pkg/scheme" +) + +func NewGVKBuilder(scheme *runtime.Scheme, shortcutExpander meta.RESTMapper) externaldeps.GVKBuilder { + return &GVKBuilder{ + scheme: scheme, + shortcutExpander: shortcutExpander, + } +} + +type GVKBuilder struct { + scheme *runtime.Scheme + shortcutExpander meta.RESTMapper +} + +func (b *GVKBuilder) BuildFromResource(resource string) (*schema.GroupVersionKind, error) { + gvr, err := b.parseGVR(resource) + if err != nil { + return nil, fmt.Errorf("error parsing GroupVersionResource: %w", err) + } + + gvk, err := b.gvrToGvk(*gvr) + if err != nil { + return nil, fmt.Errorf("error converting GroupVersionResource to GroupVersionKind: %w", err) + } + + return gvk, nil +} + +func (b *GVKBuilder) parseGVR(resource string) (*schema.GroupVersionResource, error) { + var groupVersionResource schema.GroupVersionResource + if gvr, gr := schema.ParseResourceArg(resource); gvr != nil { + groupVersionResource = *gvr + } else { + if gr.Resource == "" { + return nil, fmt.Errorf("resource type not specified") + } + + if gr.Group != "" { + if !scheme.Scheme.IsGroupRegistered(gr.Group) { + return nil, fmt.Errorf("resource group %q is not registered", gr.Group) + } + groupVersionResource = scheme.Scheme.PrioritizedVersionsForGroup(gr.Group)[0].WithResource(gr.Resource) + } else { + groupVersionResource = gr.WithVersion("") + } + } + + return &groupVersionResource, nil +} + +func (b *GVKBuilder) gvrToGvk(groupVersionResource schema.GroupVersionResource) (*schema.GroupVersionKind, error) { + var groupVersionKind schema.GroupVersionKind + if preferredKinds, err := b.shortcutExpander.KindsFor(groupVersionResource); err != nil { + return nil, fmt.Errorf("error matching a group/version/resource: %w", err) + } else if len(preferredKinds) == 0 { + return nil, fmt.Errorf("no matches for group/version/resource") + } else { + groupVersionKind = preferredKinds[0] + } + + return &groupVersionKind, nil +} diff --git a/pkg/deploy/helm/resources_waiter.go b/pkg/deploy/helm/resources_waiter.go index ad32169113..d8e720feab 100644 --- a/pkg/deploy/helm/resources_waiter.go +++ b/pkg/deploy/helm/resources_waiter.go @@ -23,7 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/resource" - "k8s.io/kubectl/pkg/scheme" + "k8s.io/client-go/kubernetes/scheme" "github.com/werf/kubedog/pkg/kube" "github.com/werf/kubedog/pkg/tracker" @@ -61,7 +61,7 @@ func extractSpecReplicas(specReplicas *int32) int { return 1 } -func (waiter *ResourcesWaiter) Wait(ctx context.Context, namespace string, resources helm_kube.ResourceList, timeout time.Duration) error { +func (waiter *ResourcesWaiter) Wait(ctx context.Context, resources helm_kube.ResourceList, timeout time.Duration) error { if os.Getenv("WERF_DISABLE_RESOURCES_WAITER") == "1" { return nil } @@ -189,7 +189,7 @@ func (waiter *ResourcesWaiter) Wait(ctx context.Context, namespace string, resou // NOTE: use context from resources-waiter object here, will be changed in helm 3 logboek.Context(ctx).LogOptionalLn() - return logboek.Context(ctx).LogProcess("Waiting for release resources to become ready"). + return logboek.Context(ctx).LogProcess("Waiting for resources to become ready"). DoError(func() error { return multitrack.Multitrack(kube.Client, specs, multitrack.MultitrackOptions{ StatusProgressPeriod: waiter.StatusProgressPeriod, @@ -361,7 +361,7 @@ mainLoop: return multitrackSpec, nil } -func (waiter *ResourcesWaiter) WatchUntilReady(ctx context.Context, namespace string, resources helm_kube.ResourceList, timeout time.Duration) error { +func (waiter *ResourcesWaiter) WatchUntilReady(ctx context.Context, resources helm_kube.ResourceList, timeout time.Duration) error { if waiter.KubeInitializer != nil { if err := waiter.KubeInitializer.Init(ctx); err != nil { return fmt.Errorf("kube initializer failed: %w", err) diff --git a/pkg/deploy/helm/stages_splitter.go b/pkg/deploy/helm/stages_splitter.go index 71a3c4d2c3..517c07619d 100644 --- a/pkg/deploy/helm/stages_splitter.go +++ b/pkg/deploy/helm/stages_splitter.go @@ -6,29 +6,31 @@ import ( "strconv" "helm.sh/helm/v3/pkg/kube" - "helm.sh/helm/v3/pkg/phasemanagers/stages" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" + "helm.sh/helm/v3/pkg/phases/stages" "k8s.io/cli-runtime/pkg/resource" ) +func NewStagesSplitter() *StagesSplitter { + return &StagesSplitter{} +} + type StagesSplitter struct{} -func (s StagesSplitter) Split(resources kube.ResourceList) (stages.SortedStageList, error) { +func (s *StagesSplitter) Split(resources kube.ResourceList) (stages.SortedStageList, error) { var stageList stages.SortedStageList - if err := resources.Visit(func(res *resource.Info, err error) error { + + if err := resources.Visit(func(resInfo *resource.Info, err error) error { if err != nil { return err } - unstructuredObj := unstructured.Unstructured{} - unstructuredObj.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(res.Object) + annotations, err := metadataAccessor.Annotations(resInfo.Object) if err != nil { - return fmt.Errorf("error converting object to unstructured type: %w", err) + return fmt.Errorf("error getting annotations for object: %w", err) } var weight int - if w, ok := unstructuredObj.GetAnnotations()[StageWeightAnnoName]; ok { + if w, ok := annotations[StageWeightAnnoName]; ok { weight, err = strconv.Atoi(w) if err != nil { return fmt.Errorf("error parsing annotation \"%s: %s\" — value should be an integer: %w", StageWeightAnnoName, w, err) @@ -44,7 +46,7 @@ func (s StagesSplitter) Split(resources kube.ResourceList) (stages.SortedStageLi stageList = append(stageList, stage) } - stage.DesiredResources.Append(res) + stage.DesiredResources.Append(resInfo) return nil }); err != nil {