diff --git a/pkg/apis/build/v1alpha1/buildrun_conversion.go b/pkg/apis/build/v1alpha1/buildrun_conversion.go new file mode 100644 index 0000000000..59bba55475 --- /dev/null +++ b/pkg/apis/build/v1alpha1/buildrun_conversion.go @@ -0,0 +1,24 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + "context" + "fmt" + + "github.com/shipwright-io/build/pkg/webhook" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +// ensure v1beta1 implements the Conversion interface +var _ webhook.Conversion = (*BuildRun)(nil) + +func (src *BuildRun) ConvertTo(ctx context.Context, obj *unstructured.Unstructured) error { + return fmt.Errorf("v1alpha1 is the current storage version, nothing to convert to") +} + +func (src *BuildRun) ConvertFrom(ctx context.Context, obj *unstructured.Unstructured) error { + return fmt.Errorf("v1alpha1 is the current storage version, nothing to convert from") +} diff --git a/pkg/apis/build/v1alpha1/buildstrategy_conversion.go b/pkg/apis/build/v1alpha1/buildstrategy_conversion.go new file mode 100644 index 0000000000..51e5d430ee --- /dev/null +++ b/pkg/apis/build/v1alpha1/buildstrategy_conversion.go @@ -0,0 +1,24 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + "context" + "fmt" + + "github.com/shipwright-io/build/pkg/webhook" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +// ensure v1beta1 implements the Conversion interface +var _ webhook.Conversion = (*BuildStrategy)(nil) + +func (src *BuildStrategy) ConvertTo(ctx context.Context, obj *unstructured.Unstructured) error { + return fmt.Errorf("v1alpha1 is the current storage version, nothing to convert to") +} + +func (src *BuildStrategy) ConvertFrom(ctx context.Context, obj *unstructured.Unstructured) error { + return fmt.Errorf("v1alpha1 is the current storage version, nothing to convert from") +} diff --git a/pkg/apis/build/v1alpha1/clusterbuildstrategy_conversion.go b/pkg/apis/build/v1alpha1/clusterbuildstrategy_conversion.go new file mode 100644 index 0000000000..37dca2a7f4 --- /dev/null +++ b/pkg/apis/build/v1alpha1/clusterbuildstrategy_conversion.go @@ -0,0 +1,24 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + "context" + "fmt" + + "github.com/shipwright-io/build/pkg/webhook" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +// ensure v1beta1 implements the Conversion interface +var _ webhook.Conversion = (*ClusterBuildStrategy)(nil) + +func (src *ClusterBuildStrategy) ConvertTo(ctx context.Context, obj *unstructured.Unstructured) error { + return fmt.Errorf("v1alpha1 is the current storage version, nothing to convert to") +} + +func (src *ClusterBuildStrategy) ConvertFrom(ctx context.Context, obj *unstructured.Unstructured) error { + return fmt.Errorf("v1alpha1 is the current storage version, nothing to convert from") +} diff --git a/pkg/apis/build/v1beta1/buildrun_conversion.go b/pkg/apis/build/v1beta1/buildrun_conversion.go index 114d0decf7..88f1a135ed 100644 --- a/pkg/apis/build/v1beta1/buildrun_conversion.go +++ b/pkg/apis/build/v1beta1/buildrun_conversion.go @@ -191,6 +191,8 @@ func (dest *BuildRunSpec) ConvertFrom(orig *v1alpha1.BuildRunSpec) error { dest.Output = &Image{} if orig.Output != nil { dest.Output.Image = orig.Output.Image + dest.Output.Annotations = orig.Output.Annotations + dest.Output.Labels = orig.Output.Labels } if orig.Output != nil && orig.Output.Credentials != nil { @@ -207,10 +209,12 @@ func (dest *BuildRunSpec) ConvertFrom(orig *v1alpha1.BuildRunSpec) error { dest.Retention = (*BuildRunRetention)(orig.Retention) // BuildRunSpec Volumes - for i, vol := range orig.Volumes { - dest.Volumes[i].Name = vol.Name - dest.Volumes[i].VolumeSource = vol.VolumeSource - + dest.Volumes = []BuildVolume{} + for _, vol := range orig.Volumes { + dest.Volumes = append(dest.Volumes, BuildVolume{ + Name: vol.Name, + VolumeSource: vol.VolumeSource, + }) } return nil } diff --git a/pkg/apis/build/v1beta1/buildstrategy_conversion.go b/pkg/apis/build/v1beta1/buildstrategy_conversion.go index 811ba87e40..b0e7ec1639 100644 --- a/pkg/apis/build/v1beta1/buildstrategy_conversion.go +++ b/pkg/apis/build/v1beta1/buildstrategy_conversion.go @@ -5,18 +5,144 @@ package v1beta1 import ( - "sigs.k8s.io/controller-runtime/pkg/conversion" + "context" + + "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" + "github.com/shipwright-io/build/pkg/ctxlog" + "github.com/shipwright-io/build/pkg/webhook" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + runtime "k8s.io/apimachinery/pkg/runtime" ) -// ConvertTo converts this BuildStrategy to the Hub version (v1alpha1) -func (src *BuildStrategy) ConvertTo(dstRaw conversion.Hub) error { - // dst := dstRaw.(*v1alpha1.BuildStrategy) +// ensure v1beta1 implements the Conversion interface +var _ webhook.Conversion = (*BuildStrategy)(nil) + +// To Alpha +func (src *BuildStrategy) ConvertTo(ctx context.Context, obj *unstructured.Unstructured) error { + var bs v1alpha1.BuildStrategy + bs.TypeMeta = src.TypeMeta + bs.TypeMeta.APIVersion = ALPHA_GROUP_VERSION + bs.ObjectMeta = src.ObjectMeta + + bs.Spec.BuildSteps = []v1alpha1.BuildStep{} + for _, step := range src.Spec.Steps { + + buildStep := v1alpha1.BuildStep{ + Container: corev1.Container{ + Name: step.Name, + Image: step.Image, + Command: step.Command, + Args: step.Args, + WorkingDir: step.WorkingDir, + Env: step.Env, + Resources: step.Resources, + VolumeMounts: step.VolumeMounts, + ImagePullPolicy: step.ImagePullPolicy, + }, + } + + if step.SecurityContext != nil { + buildStep.SecurityContext = step.SecurityContext + } + + bs.Spec.BuildSteps = append(bs.Spec.BuildSteps, buildStep) + } + + bs.Spec.Parameters = []v1alpha1.Parameter{} + for _, param := range src.Spec.Parameters { + bs.Spec.Parameters = append(bs.Spec.Parameters, v1alpha1.Parameter{ + Name: param.Name, + Description: param.Description, + Type: v1alpha1.ParameterType(param.Type), + Default: param.Default, + Defaults: param.Defaults, + }) + } + + if src.Spec.SecurityContext != nil { + bs.Spec.SecurityContext = (*v1alpha1.BuildStrategySecurityContext)(src.Spec.SecurityContext) + } + + bs.Spec.Volumes = []v1alpha1.BuildStrategyVolume{} + for _, vol := range src.Spec.Volumes { + bs.Spec.Volumes = append(bs.Spec.Volumes, v1alpha1.BuildStrategyVolume{ + Overridable: vol.Overridable, + Name: vol.Name, + Description: &vol.Name, + VolumeSource: vol.VolumeSource, + }) + } + + mapito, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&bs) + if err != nil { + ctxlog.Error(ctx, err, "failed structuring the newObject") + } + obj.Object = mapito return nil } -// ConvertFrom converts from the Hub version (v1alpha1) to this version. -// TODO: Not needed? -func (dst *BuildStrategy) ConvertFrom(srcRaw conversion.Hub) error { +// From Alpha +func (src *BuildStrategy) ConvertFrom(ctx context.Context, obj *unstructured.Unstructured) error { + var br v1alpha1.BuildStrategy + + unstructured := obj.UnstructuredContent() + err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &br) + if err != nil { + ctxlog.Error(ctx, err, "failed unstructuring the buildrun convertedObject") + } + + src.ObjectMeta = br.ObjectMeta + src.TypeMeta = br.TypeMeta + src.TypeMeta.APIVersion = BETA_GROUP_VERSION + + src.Spec.Steps = []Step{} + for _, brStep := range br.Spec.BuildSteps { + + step := Step{ + Name: brStep.Name, + Image: brStep.Image, + Command: brStep.Command, + Args: brStep.Args, + WorkingDir: brStep.WorkingDir, + Env: brStep.Env, + Resources: brStep.Resources, + VolumeMounts: brStep.VolumeMounts, + ImagePullPolicy: brStep.ImagePullPolicy, + } + + if brStep.SecurityContext != nil { + step.SecurityContext = brStep.SecurityContext + } + + src.Spec.Steps = append(src.Spec.Steps, step) + } + + src.Spec.Parameters = []Parameter{} + for _, param := range br.Spec.Parameters { + src.Spec.Parameters = append(src.Spec.Parameters, Parameter{ + Name: param.Name, + Description: param.Description, + Type: ParameterType(param.Type), + Default: param.Default, + Defaults: param.Defaults, + }) + } + + if br.Spec.SecurityContext != nil { + src.Spec.SecurityContext = (*BuildStrategySecurityContext)(br.Spec.SecurityContext) + } + + src.Spec.Volumes = []BuildStrategyVolume{} + for _, vol := range br.Spec.Volumes { + src.Spec.Volumes = append(src.Spec.Volumes, BuildStrategyVolume{ + Overridable: vol.Overridable, + Name: vol.Name, + Description: &vol.Name, + VolumeSource: vol.VolumeSource, + }) + } + return nil } diff --git a/pkg/apis/build/v1beta1/clusterbuildstrategy_conversion.go b/pkg/apis/build/v1beta1/clusterbuildstrategy_conversion.go index 6fdfb2fee9..c02aa6e79e 100644 --- a/pkg/apis/build/v1beta1/clusterbuildstrategy_conversion.go +++ b/pkg/apis/build/v1beta1/clusterbuildstrategy_conversion.go @@ -5,18 +5,144 @@ package v1beta1 import ( - "sigs.k8s.io/controller-runtime/pkg/conversion" + "context" + + "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" + "github.com/shipwright-io/build/pkg/ctxlog" + "github.com/shipwright-io/build/pkg/webhook" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + runtime "k8s.io/apimachinery/pkg/runtime" ) -// ConvertTo converts this ClusterBuildStrategy to the Hub version (v1alpha1) -func (src *ClusterBuildStrategy) ConvertTo(dstRaw conversion.Hub) error { - // dst := dstRaw.(*v1alpha1.ClusterBuildStrategy) +// ensure v1beta1 implements the Conversion interface +var _ webhook.Conversion = (*ClusterBuildStrategy)(nil) + +// To Alpha +func (src *ClusterBuildStrategy) ConvertTo(ctx context.Context, obj *unstructured.Unstructured) error { + var bs v1alpha1.ClusterBuildStrategy + bs.TypeMeta = src.TypeMeta + bs.TypeMeta.APIVersion = ALPHA_GROUP_VERSION + bs.ObjectMeta = src.ObjectMeta + + bs.Spec.BuildSteps = []v1alpha1.BuildStep{} + for _, step := range src.Spec.Steps { + + buildStep := v1alpha1.BuildStep{ + Container: corev1.Container{ + Name: step.Name, + Image: step.Image, + Command: step.Command, + Args: step.Args, + WorkingDir: step.WorkingDir, + Env: step.Env, + Resources: step.Resources, + VolumeMounts: step.VolumeMounts, + ImagePullPolicy: step.ImagePullPolicy, + }, + } + + if step.SecurityContext != nil { + buildStep.SecurityContext = step.SecurityContext + } + + bs.Spec.BuildSteps = append(bs.Spec.BuildSteps, buildStep) + } + + bs.Spec.Parameters = []v1alpha1.Parameter{} + for _, param := range src.Spec.Parameters { + bs.Spec.Parameters = append(bs.Spec.Parameters, v1alpha1.Parameter{ + Name: param.Name, + Description: param.Description, + Type: v1alpha1.ParameterType(param.Type), + Default: param.Default, + Defaults: param.Defaults, + }) + } + + if src.Spec.SecurityContext != nil { + bs.Spec.SecurityContext = (*v1alpha1.BuildStrategySecurityContext)(src.Spec.SecurityContext) + } + + bs.Spec.Volumes = []v1alpha1.BuildStrategyVolume{} + for _, vol := range src.Spec.Volumes { + bs.Spec.Volumes = append(bs.Spec.Volumes, v1alpha1.BuildStrategyVolume{ + Overridable: vol.Overridable, + Name: vol.Name, + Description: &vol.Name, + VolumeSource: vol.VolumeSource, + }) + } + + mapito, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&bs) + if err != nil { + ctxlog.Error(ctx, err, "failed structuring the newObject") + } + obj.Object = mapito return nil } -// ConvertFrom converts from the Hub version (v1alpha1) to this version. -// TODO: Not needed? -func (dst *ClusterBuildStrategy) ConvertFrom(srcRaw conversion.Hub) error { +// From Alpha +func (src *ClusterBuildStrategy) ConvertFrom(ctx context.Context, obj *unstructured.Unstructured) error { + var br v1alpha1.ClusterBuildStrategy + + unstructured := obj.UnstructuredContent() + err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &br) + if err != nil { + ctxlog.Error(ctx, err, "failed unstructuring the buildrun convertedObject") + } + + src.ObjectMeta = br.ObjectMeta + src.TypeMeta = br.TypeMeta + src.TypeMeta.APIVersion = BETA_GROUP_VERSION + + src.Spec.Steps = []Step{} + for _, brStep := range br.Spec.BuildSteps { + + step := Step{ + Name: brStep.Name, + Image: brStep.Image, + Command: brStep.Command, + Args: brStep.Args, + WorkingDir: brStep.WorkingDir, + Env: brStep.Env, + Resources: brStep.Resources, + VolumeMounts: brStep.VolumeMounts, + ImagePullPolicy: brStep.ImagePullPolicy, + } + + if brStep.SecurityContext != nil { + step.SecurityContext = brStep.SecurityContext + } + + src.Spec.Steps = append(src.Spec.Steps, step) + } + + src.Spec.Parameters = []Parameter{} + for _, param := range br.Spec.Parameters { + src.Spec.Parameters = append(src.Spec.Parameters, Parameter{ + Name: param.Name, + Description: param.Description, + Type: ParameterType(param.Type), + Default: param.Default, + Defaults: param.Defaults, + }) + } + + if br.Spec.SecurityContext != nil { + src.Spec.SecurityContext = (*BuildStrategySecurityContext)(br.Spec.SecurityContext) + } + + src.Spec.Volumes = []BuildStrategyVolume{} + for _, vol := range br.Spec.Volumes { + src.Spec.Volumes = append(src.Spec.Volumes, BuildStrategyVolume{ + Overridable: vol.Overridable, + Name: vol.Name, + Description: &vol.Name, + VolumeSource: vol.VolumeSource, + }) + } + return nil } diff --git a/pkg/webhook/conversion/converter.go b/pkg/webhook/conversion/converter.go index e1c6efdcfe..8f0605616e 100644 --- a/pkg/webhook/conversion/converter.go +++ b/pkg/webhook/conversion/converter.go @@ -16,11 +16,13 @@ import ( ) const ( - BETA_GROUP_VERSION = "shipwright.io/v1beta1" - ALPHA_GROUP_VERSION = "shipwright.io/v1alpha1" - BUILD_KIND = "Build" - BUILDRUN_KIND = "BuildRun" - KIND = "kind" + BETA_GROUP_VERSION = "shipwright.io/v1beta1" + ALPHA_GROUP_VERSION = "shipwright.io/v1alpha1" + BUILD_KIND = "Build" + BUILDRUN_KIND = "BuildRun" + BUILDSTRATEGY_KIND = "BuildStrategy" + CLUSTERBUILDSTRATEGY_KIND = "ClusterBuildStrategy" + KIND = "kind" ) // convertSHPCR takes an unstructured object with certain CR apiversion, parses it to a known Object type, @@ -60,6 +62,23 @@ func convertSHPCR(Object *unstructured.Unstructured, toVersion string, ctx conte } buildRun.ConvertTo(ctx, convertedObject) + } else if convertedObject.Object[KIND] == BUILDSTRATEGY_KIND { + unstructured := convertedObject.UnstructuredContent() + var buildStrategy v1beta1.BuildStrategy + err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &buildStrategy) + if err != nil { + ctxlog.Error(ctx, err, "failed unstructuring the buildStrategy convertedObject") + } + buildStrategy.ConvertTo(ctx, convertedObject) + + } else if convertedObject.Object[KIND] == CLUSTERBUILDSTRATEGY_KIND { + unstructured := convertedObject.UnstructuredContent() + var clusterBuildStrategy v1beta1.ClusterBuildStrategy + err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructured, &clusterBuildStrategy) + if err != nil { + ctxlog.Error(ctx, err, "failed unstructuring the clusterBuildStrategy convertedObject") + } + clusterBuildStrategy.ConvertTo(ctx, convertedObject) } else { return nil, statusErrorWithMessage("unsupporteddda skdksdjkjsd Kind") } @@ -91,6 +110,27 @@ func convertSHPCR(Object *unstructured.Unstructured, toVersion string, ctx conte ctxlog.Error(ctx, err, "failed structuring the newObject") } convertedObject.Object = mapito + } else if convertedObject.Object[KIND] == BUILDSTRATEGY_KIND { + var buildStrategyBeta v1beta1.BuildStrategy + + buildStrategyBeta.ConvertFrom(ctx, convertedObject) + + mapito, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&buildStrategyBeta) + if err != nil { + ctxlog.Error(ctx, err, "failed structuring the newObject") + } + convertedObject.Object = mapito + + } else if convertedObject.Object[KIND] == CLUSTERBUILDSTRATEGY_KIND { + var clusterBuildStrategyBeta v1beta1.ClusterBuildStrategy + + clusterBuildStrategyBeta.ConvertFrom(ctx, convertedObject) + + mapito, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&clusterBuildStrategyBeta) + if err != nil { + ctxlog.Error(ctx, err, "failed structuring the newObject") + } + convertedObject.Object = mapito } else { return nil, statusErrorWithMessage("unsupported Kind") } diff --git a/pkg/webhook/conversion/converter_test.go b/pkg/webhook/conversion/converter_test.go index cfb935c399..39f6ad493e 100644 --- a/pkg/webhook/conversion/converter_test.go +++ b/pkg/webhook/conversion/converter_test.go @@ -699,6 +699,75 @@ request: Expect(buildRun.Spec.Volumes[0].Name).To(Equal("volume1")) }) }) + Context("for a BuildRun CR from v1alpha1 to v1beta1", func() { + var desiredAPIVersion = "shipwright.io/v1beta1" + It("converts for spec Build buildref", func() { + buildName := "a_build" + sa := "foobar" + timeout := "10m" + buildTemplate := `kind: ConversionReview +apiVersion: %s +request: + uid: 0000-0000-0000-0000 + desiredAPIVersion: %s + objects: + - apiVersion: shipwright.io/v1alpha1 + kind: BuildRun + metadata: + name: buildkit-run + spec: + buildRef: + name: %s + serviceAccount: + name: %s + timeout: %s + paramValues: + - name: cache + value: registry + volumes: + - name: volume-name + configMap: + name: test-config + retention: + ttlAfterFailed: 10m + ttlAfterSucceeded: 10m + output: + image: foobar + credentials: + name: foobar + labels: + foo: bar + env: + - name: foo + value: bar +` + o := fmt.Sprintf(buildTemplate, apiVersion, + desiredAPIVersion, buildName, + sa, timeout) + + conversionReview, err := getConversionReview(o) + Expect(err).To(BeNil()) + Expect(conversionReview.Response.Result.Status).To(Equal(v1.StatusSuccess)) + + convertedObj, err := ToUnstructured(conversionReview) + Expect(err).To(BeNil()) + + buildRun, err := toV1Beta1BuildRunObject(convertedObj) + Expect(err).To(BeNil()) + + Expect(buildRun.Spec.Retention.TTLAfterFailed.Duration).To(Equal(time.Duration(10 * time.Minute))) + Expect(buildRun.Spec.Retention.TTLAfterSucceeded.Duration).To(Equal(time.Duration(10 * time.Minute))) + Expect(buildRun.Spec.Build.Name).To(Equal(buildName)) + Expect(buildRun.Spec.ServiceAccount).To(Equal(&sa)) + Expect(buildRun.Spec.Timeout.Duration).To(Equal(time.Duration(10 * time.Minute))) + Expect(len(buildRun.Spec.Env)).To(Equal(1)) + Expect(len(buildRun.Spec.Volumes)).To(Equal(1)) + Expect(buildRun.Spec.Output.PushSecret).To(Equal(&sa)) + Expect(buildRun.Spec.Output.Image).To(Equal(sa)) + Expect(buildRun.Spec.Output.Labels).To(Equal(map[string]string{"foo": "bar"})) + Expect(len(buildRun.Spec.ParamValues)).To(Equal(1)) + }) + }) }) func ToUnstructured(conversionReview apiextensionsv1.ConversionReview) (unstructured.Unstructured, error) { @@ -730,6 +799,15 @@ func toV1Alpha1BuildRunObject(convertedObject unstructured.Unstructured) (v1alph return build, nil } +func toV1Beta1BuildRunObject(convertedObject unstructured.Unstructured) (v1beta1.BuildRun, error) { + var build v1beta1.BuildRun + u := convertedObject.UnstructuredContent() + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u, &build); err != nil { + return build, err + } + return build, nil +} + func toV1Beta1BuildObject(convertedObject unstructured.Unstructured) (v1beta1.Build, error) { var build v1beta1.Build u := convertedObject.UnstructuredContent()