diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/config/application.go b/pkg/app/pipedv1/plugin/kubernetes_multicluster/config/application.go index 034d849011..0b34b51361 100644 --- a/pkg/app/pipedv1/plugin/kubernetes_multicluster/config/application.go +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/config/application.go @@ -201,6 +201,9 @@ type K8sCanaryRolloutStageOptions struct { // K8sCanaryCleanStageOptions contains all configurable values for a K8S_CANARY_CLEAN stage. type K8sCanaryCleanStageOptions struct{} +// K8sBaselineCleanStageOptions contains all configurable values for a K8S_BASELINE_CLEAN stage. +type K8sBaselineCleanStageOptions struct{} + // K8sResourcePatch represents a patch operation for a Kubernetes resource. type K8sResourcePatch struct { // The target of the patch operation. diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/baseline.go b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/baseline.go new file mode 100644 index 0000000000..fcffbfc925 --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/baseline.go @@ -0,0 +1,113 @@ +// Copyright 2025 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package deployment + +import ( + "cmp" + "context" + "fmt" + + "golang.org/x/sync/errgroup" + + sdk "github.com/pipe-cd/piped-plugin-sdk-go" + + kubeconfig "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes_multicluster/config" + "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes_multicluster/provider" + "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes_multicluster/toolregistry" +) + +func (p *Plugin) executeK8sMultiBaselineCleanStage(ctx context.Context, input *sdk.ExecuteStageInput[kubeconfig.KubernetesApplicationSpec], dts []*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]) sdk.StageStatus { + lp := input.Client.LogPersister() + + cfg, err := input.Request.TargetDeploymentSource.AppConfig() + if err != nil { + lp.Errorf("Failed while decoding application config (%v)", err) + return sdk.StageStatusFailure + } + + deployTargetMap := make(map[string]*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig], len(dts)) + for _, dt := range dts { + deployTargetMap[dt.Name] = dt + } + + type targetConfig struct { + deployTarget *sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig] + } + + targetConfigs := make([]targetConfig, 0, len(dts)) + if len(cfg.Spec.Input.MultiTargets) == 0 { + for _, dt := range dts { + targetConfigs = append(targetConfigs, targetConfig{deployTarget: dt}) + } + } else { + for _, mt := range cfg.Spec.Input.MultiTargets { + dt, ok := deployTargetMap[mt.Target.Name] + if !ok { + lp.Infof("Ignore multi target '%s': not matched any deployTarget", mt.Target.Name) + continue + } + targetConfigs = append(targetConfigs, targetConfig{deployTarget: dt}) + } + } + + eg, ctx := errgroup.WithContext(ctx) + for _, tc := range targetConfigs { + eg.Go(func() error { + lp.Infof("Start cleaning BASELINE variant on target %s", tc.deployTarget.Name) + if err := p.baselineClean(ctx, input, tc.deployTarget, cfg); err != nil { + return fmt.Errorf("failed to clean BASELINE variant on target %s: %w", tc.deployTarget.Name, err) + } + return nil + }) + } + + if err := eg.Wait(); err != nil { + lp.Errorf("Failed while cleaning BASELINE variant (%v)", err) + return sdk.StageStatusFailure + } + + return sdk.StageStatusSuccess +} + +func (p *Plugin) baselineClean( + ctx context.Context, + input *sdk.ExecuteStageInput[kubeconfig.KubernetesApplicationSpec], + dt *sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig], + cfg *sdk.ApplicationConfig[kubeconfig.KubernetesApplicationSpec], +) error { + lp := input.Client.LogPersister() + + var ( + appCfg = cfg.Spec + variantLabel = appCfg.VariantLabel.Key + baselineVariant = appCfg.VariantLabel.BaselineValue + ) + + toolRegistry := toolregistry.NewRegistry(input.Client.ToolRegistry()) + + kubectlPath, err := toolRegistry.Kubectl(ctx, cmp.Or(appCfg.Input.KubectlVersion, dt.Config.KubectlVersion)) + if err != nil { + return fmt.Errorf("failed while getting kubectl tool: %w", err) + } + + kubectl := provider.NewKubectl(kubectlPath) + applier := provider.NewApplier(kubectl, appCfg.Input, dt.Config, input.Logger) + + if err := deleteVariantResources(ctx, lp, kubectl, dt.Config.KubeConfigPath, applier, input.Request.Deployment.ApplicationID, variantLabel, baselineVariant); err != nil { + return fmt.Errorf("unable to remove baseline resources: %w", err) + } + + return nil +} diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/baseline_test.go b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/baseline_test.go new file mode 100644 index 0000000000..85d719e3b2 --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/baseline_test.go @@ -0,0 +1,334 @@ +// Copyright 2025 The PipeCD Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package deployment + +import ( + "context" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + + sdk "github.com/pipe-cd/piped-plugin-sdk-go" + "github.com/pipe-cd/piped-plugin-sdk-go/logpersister/logpersistertest" + "github.com/pipe-cd/piped-plugin-sdk-go/toolregistry/toolregistrytest" + + kubeconfig "github.com/pipe-cd/pipecd/pkg/app/pipedv1/plugin/kubernetes_multicluster/config" +) + +// baselineDeployment builds a pre-created baseline Deployment for test setup. +func baselineDeployment(namespace string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]any{ + "name": "simple-baseline", + "namespace": namespace, + "labels": map[string]any{ + "app": "simple", + "pipecd.dev/managed-by": "piped", + "pipecd.dev/piped": "piped-id", + "pipecd.dev/application": "app-id", + "pipecd.dev/variant": "baseline", + }, + "annotations": map[string]any{ + "pipecd.dev/managed-by": "piped", + "pipecd.dev/application": "app-id", + "pipecd.dev/variant": "baseline", + }, + }, + "spec": map[string]any{ + "replicas": int64(1), + "selector": map[string]any{ + "matchLabels": map[string]any{ + "app": "simple", + "pipecd.dev/variant": "baseline", + }, + }, + "template": map[string]any{ + "metadata": map[string]any{ + "labels": map[string]any{ + "app": "simple", + "pipecd.dev/variant": "baseline", + }, + }, + "spec": map[string]any{ + "containers": []any{ + map[string]any{ + "name": "helloworld", + "image": "ghcr.io/pipe-cd/helloworld:v0.32.0", + }, + }, + }, + }, + }, + }, + } +} + +// baselineService builds a pre-created baseline Service for test setup. +func baselineService(namespace string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "Service", + "metadata": map[string]any{ + "name": "simple-baseline", + "namespace": namespace, + "labels": map[string]any{ + "app": "simple", + "pipecd.dev/managed-by": "piped", + "pipecd.dev/piped": "piped-id", + "pipecd.dev/application": "app-id", + "pipecd.dev/variant": "baseline", + }, + "annotations": map[string]any{ + "pipecd.dev/managed-by": "piped", + "pipecd.dev/application": "app-id", + "pipecd.dev/variant": "baseline", + }, + }, + "spec": map[string]any{ + "selector": map[string]any{ + "app": "simple", + "pipecd.dev/variant": "baseline", + }, + "ports": []any{ + map[string]any{ + "protocol": "TCP", + "port": int64(9085), + "targetPort": int64(9085), + }, + }, + }, + }, + } +} + +func TestPlugin_executeK8sMultiBaselineCleanStage(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testRegistry := toolregistrytest.NewTestToolRegistry(t) + + appCfg := sdk.LoadApplicationConfigForTest[kubeconfig.KubernetesApplicationSpec](t, filepath.Join("testdata", "simple", "app.pipecd.yaml"), "kubernetes_multicluster") + + input := &sdk.ExecuteStageInput[kubeconfig.KubernetesApplicationSpec]{ + Request: sdk.ExecuteStageRequest[kubeconfig.KubernetesApplicationSpec]{ + StageName: StageK8sMultiBaselineClean, + StageConfig: []byte(`{}`), + TargetDeploymentSource: sdk.DeploymentSource[kubeconfig.KubernetesApplicationSpec]{ + ApplicationDirectory: filepath.Join("testdata", "simple"), + CommitHash: "0123456789", + ApplicationConfig: appCfg, + ApplicationConfigFilename: "app.pipecd.yaml", + }, + Deployment: sdk.Deployment{ + PipedID: "piped-id", + ApplicationID: "app-id", + }, + }, + Client: sdk.NewClient(nil, "kubernetes_multicluster", "", "", logpersistertest.NewTestLogPersister(t), testRegistry), + Logger: zaptest.NewLogger(t), + } + + dtConfig, dynamicClient := setupTestDeployTargetConfigAndDynamicClient(t) + + deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} + + // Pre-create the baseline deployment (simulating what K8S_BASELINE_ROLLOUT would have done). + _, err := dynamicClient.Resource(deploymentRes).Namespace("default").Create(ctx, baselineDeployment("default"), metav1.CreateOptions{}) + require.NoError(t, err) + + _, err = dynamicClient.Resource(deploymentRes).Namespace("default").Get(ctx, "simple-baseline", metav1.GetOptions{}) + require.NoError(t, err) + + plugin := &Plugin{} + status := plugin.executeK8sMultiBaselineCleanStage(ctx, input, []*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]{ + {Name: "default", Config: *dtConfig}, + }) + + assert.Equal(t, sdk.StageStatusSuccess, status) + + _, err = dynamicClient.Resource(deploymentRes).Namespace("default").Get(ctx, "simple-baseline", metav1.GetOptions{}) + require.Error(t, err) + assert.True(t, k8serrors.IsNotFound(err)) +} + +func TestPlugin_executeK8sMultiBaselineCleanStage_multipleTargets(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testRegistry := toolregistrytest.NewTestToolRegistry(t) + + appCfg := sdk.LoadApplicationConfigForTest[kubeconfig.KubernetesApplicationSpec](t, filepath.Join("testdata", "simple", "app.pipecd.yaml"), "kubernetes_multicluster") + + clusterUS := setupCluster(t, "cluster-us") + clusterEU := setupCluster(t, "cluster-eu") + + input := &sdk.ExecuteStageInput[kubeconfig.KubernetesApplicationSpec]{ + Request: sdk.ExecuteStageRequest[kubeconfig.KubernetesApplicationSpec]{ + StageName: StageK8sMultiBaselineClean, + StageConfig: []byte(`{}`), + TargetDeploymentSource: sdk.DeploymentSource[kubeconfig.KubernetesApplicationSpec]{ + ApplicationDirectory: filepath.Join("testdata", "simple"), + CommitHash: "0123456789", + ApplicationConfig: appCfg, + ApplicationConfigFilename: "app.pipecd.yaml", + }, + Deployment: sdk.Deployment{ + PipedID: "piped-id", + ApplicationID: "app-id", + }, + }, + Client: sdk.NewClient(nil, "kubernetes_multicluster", "", "", logpersistertest.NewTestLogPersister(t), testRegistry), + Logger: zaptest.NewLogger(t), + } + + deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} + + for _, c := range []*cluster{clusterUS, clusterEU} { + _, err := c.cli.Resource(deploymentRes).Namespace("default").Create(ctx, baselineDeployment("default"), metav1.CreateOptions{}) + require.NoError(t, err) + } + + plugin := &Plugin{} + status := plugin.executeK8sMultiBaselineCleanStage(ctx, input, []*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]{ + {Name: clusterUS.name, Config: *clusterUS.dtc}, + {Name: clusterEU.name, Config: *clusterEU.dtc}, + }) + + assert.Equal(t, sdk.StageStatusSuccess, status) + + for _, c := range []*cluster{clusterUS, clusterEU} { + _, err := c.cli.Resource(deploymentRes).Namespace("default").Get(ctx, "simple-baseline", metav1.GetOptions{}) + require.Error(t, err) + assert.True(t, k8serrors.IsNotFound(err), "baseline deployment should be deleted on cluster %s", c.name) + } +} + +func TestPlugin_executeK8sMultiBaselineCleanStage_withCreateService(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testRegistry := toolregistrytest.NewTestToolRegistry(t) + + configDir := filepath.Join("testdata", "baseline_clean_with_create_service") + appCfg := sdk.LoadApplicationConfigForTest[kubeconfig.KubernetesApplicationSpec](t, filepath.Join(configDir, "app.pipecd.yaml"), "kubernetes_multicluster") + + input := &sdk.ExecuteStageInput[kubeconfig.KubernetesApplicationSpec]{ + Request: sdk.ExecuteStageRequest[kubeconfig.KubernetesApplicationSpec]{ + StageName: StageK8sMultiBaselineClean, + StageConfig: []byte(`{}`), + TargetDeploymentSource: sdk.DeploymentSource[kubeconfig.KubernetesApplicationSpec]{ + ApplicationDirectory: configDir, + CommitHash: "0123456789", + ApplicationConfig: appCfg, + ApplicationConfigFilename: "app.pipecd.yaml", + }, + Deployment: sdk.Deployment{ + PipedID: "piped-id", + ApplicationID: "app-id", + }, + }, + Client: sdk.NewClient(nil, "kubernetes_multicluster", "", "", logpersistertest.NewTestLogPersister(t), testRegistry), + Logger: zaptest.NewLogger(t), + } + + dtConfig, dynamicClient := setupTestDeployTargetConfigAndDynamicClient(t) + + deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} + serviceRes := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"} + + // Pre-create both baseline deployment and service. + _, err := dynamicClient.Resource(deploymentRes).Namespace("default").Create(ctx, baselineDeployment("default"), metav1.CreateOptions{}) + require.NoError(t, err) + _, err = dynamicClient.Resource(serviceRes).Namespace("default").Create(ctx, baselineService("default"), metav1.CreateOptions{}) + require.NoError(t, err) + + plugin := &Plugin{} + status := plugin.executeK8sMultiBaselineCleanStage(ctx, input, []*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]{ + {Name: "default", Config: *dtConfig}, + }) + + assert.Equal(t, sdk.StageStatusSuccess, status) + + _, err = dynamicClient.Resource(deploymentRes).Namespace("default").Get(ctx, "simple-baseline", metav1.GetOptions{}) + require.Error(t, err) + assert.True(t, k8serrors.IsNotFound(err)) + + _, err = dynamicClient.Resource(serviceRes).Namespace("default").Get(ctx, "simple-baseline", metav1.GetOptions{}) + require.Error(t, err) + assert.True(t, k8serrors.IsNotFound(err)) +} + +func TestPlugin_executeK8sMultiBaselineCleanStage_withoutCreateService(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testRegistry := toolregistrytest.NewTestToolRegistry(t) + + configDir := filepath.Join("testdata", "baseline_clean_without_create_service") + appCfg := sdk.LoadApplicationConfigForTest[kubeconfig.KubernetesApplicationSpec](t, filepath.Join(configDir, "app.pipecd.yaml"), "kubernetes_multicluster") + + input := &sdk.ExecuteStageInput[kubeconfig.KubernetesApplicationSpec]{ + Request: sdk.ExecuteStageRequest[kubeconfig.KubernetesApplicationSpec]{ + StageName: StageK8sMultiBaselineClean, + StageConfig: []byte(`{}`), + TargetDeploymentSource: sdk.DeploymentSource[kubeconfig.KubernetesApplicationSpec]{ + ApplicationDirectory: configDir, + CommitHash: "0123456789", + ApplicationConfig: appCfg, + ApplicationConfigFilename: "app.pipecd.yaml", + }, + Deployment: sdk.Deployment{ + PipedID: "piped-id", + ApplicationID: "app-id", + }, + }, + Client: sdk.NewClient(nil, "kubernetes_multicluster", "", "", logpersistertest.NewTestLogPersister(t), testRegistry), + Logger: zaptest.NewLogger(t), + } + + dtConfig, dynamicClient := setupTestDeployTargetConfigAndDynamicClient(t) + + deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} + + // Pre-create only a baseline deployment (no service). + _, err := dynamicClient.Resource(deploymentRes).Namespace("default").Create(ctx, baselineDeployment("default"), metav1.CreateOptions{}) + require.NoError(t, err) + + plugin := &Plugin{} + status := plugin.executeK8sMultiBaselineCleanStage(ctx, input, []*sdk.DeployTarget[kubeconfig.KubernetesDeployTargetConfig]{ + {Name: "default", Config: *dtConfig}, + }) + + assert.Equal(t, sdk.StageStatusSuccess, status) + + _, err = dynamicClient.Resource(deploymentRes).Namespace("default").Get(ctx, "simple-baseline", metav1.GetOptions{}) + require.Error(t, err) + assert.True(t, k8serrors.IsNotFound(err)) +} diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/pipeline.go b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/pipeline.go index 63894ae1b7..3d10c96d7f 100644 --- a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/pipeline.go +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/pipeline.go @@ -30,6 +30,8 @@ const ( StageK8sMultiCanaryRollout = "K8S_CANARY_ROLLOUT" // StageK8sMultiCanaryClean represents the state where all canary resources should be removed. StageK8sMultiCanaryClean = "K8S_CANARY_CLEAN" + // StageK8sMultiBaselineClean represents the state where all baseline resources should be removed. + StageK8sMultiBaselineClean = "K8S_BASELINE_CLEAN" ) var allStages = []string{ @@ -37,6 +39,7 @@ var allStages = []string{ StageK8sMultiRollback, StageK8sMultiCanaryRollout, StageK8sMultiCanaryClean, + StageK8sMultiBaselineClean, } const ( @@ -48,6 +51,8 @@ const ( StageDescriptionK8sMultiCanaryRollout = "Rollout the new version as CANARY to all targets" // StageDescriptionK8sMultiCanaryClean represents the description of the K8sCanaryClean stage. StageDescriptionK8sMultiCanaryClean = "Remove all canary resources" + // StageDescriptionK8sMultiBaselineClean represents the description of the K8sBaselineClean stage. + StageDescriptionK8sMultiBaselineClean = "Remove all baseline resources" ) func buildQuickSyncPipeline(autoRollback bool) []sdk.QuickSyncStage { diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/plugin.go b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/plugin.go index f1e56b3f64..ed267c9684 100644 --- a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/plugin.go +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/plugin.go @@ -73,6 +73,10 @@ func (p *Plugin) ExecuteStage(ctx context.Context, _ *sdk.ConfigNone, dts []*sdk return &sdk.ExecuteStageResponse{ Status: p.executeK8sMultiCanaryCleanStage(ctx, input, dts), }, nil + case StageK8sMultiBaselineClean: + return &sdk.ExecuteStageResponse{ + Status: p.executeK8sMultiBaselineCleanStage(ctx, input, dts), + }, nil default: return nil, errors.New("unimplemented or unsupported stage") } diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/app.pipecd.yaml b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/app.pipecd.yaml new file mode 100644 index 0000000000..3b1cd4ec8a --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/app.pipecd.yaml @@ -0,0 +1,24 @@ +apiVersion: pipecd.dev/v1beta1 +kind: KubernetesApp +spec: + name: baseline-clean + labels: + env: example + team: product + description: | + This app is test data for baseline clean with create service. + pipeline: + stages: + - name: K8S_BASELINE_ROLLOUT + with: + createService: true + - name: K8S_BASELINE_CLEAN + plugins: + kubernetes_multicluster: + input: + manifests: + - deployment.yaml + - service.yaml + kubectlVersion: 1.32.2 + service: + name: simple diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/deployment.yaml b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/deployment.yaml new file mode 100644 index 0000000000..a7b8a57fe6 --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/deployment.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: simple + labels: + app: simple +spec: + replicas: 2 + selector: + matchLabels: + app: simple + template: + metadata: + labels: + app: simple + spec: + containers: + - name: helloworld + image: ghcr.io/pipe-cd/helloworld:v0.32.0 + ports: + - containerPort: 9085 diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/service.yaml b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/service.yaml new file mode 100644 index 0000000000..52ca9d1f59 --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_with_create_service/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: simple +spec: + selector: + app: simple + ports: + - protocol: TCP + port: 9085 + targetPort: 9085 diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_without_create_service/app.pipecd.yaml b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_without_create_service/app.pipecd.yaml new file mode 100644 index 0000000000..f3ab7470ad --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_without_create_service/app.pipecd.yaml @@ -0,0 +1,19 @@ +apiVersion: pipecd.dev/v1beta1 +kind: KubernetesApp +spec: + name: baseline-clean + labels: + env: example + team: product + description: | + This app is test data for baseline clean without create service. + pipeline: + stages: + - name: K8S_BASELINE_ROLLOUT + - name: K8S_BASELINE_CLEAN + plugins: + kubernetes_multicluster: + input: + manifests: + - deployment.yaml + kubectlVersion: 1.32.2 diff --git a/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_without_create_service/deployment.yaml b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_without_create_service/deployment.yaml new file mode 100644 index 0000000000..a7b8a57fe6 --- /dev/null +++ b/pkg/app/pipedv1/plugin/kubernetes_multicluster/deployment/testdata/baseline_clean_without_create_service/deployment.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: simple + labels: + app: simple +spec: + replicas: 2 + selector: + matchLabels: + app: simple + template: + metadata: + labels: + app: simple + spec: + containers: + - name: helloworld + image: ghcr.io/pipe-cd/helloworld:v0.32.0 + ports: + - containerPort: 9085