From 1c71b95992e186db7d519b944e2acc06cfc10cf9 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Tue, 8 Nov 2022 17:44:38 -0500 Subject: [PATCH 1/5] chore: update to devworkspace-operator v0.17.0 Signed-off-by: Andrew Obuchowicz --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index ad36c0ea1..848555485 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.16 require ( github.com/Shopify/logrus-bugsnag v0.0.0-00010101000000-000000000000 // indirect github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7 - github.com/devfile/api/v2 v2.0.0-20220414122024-32cae1f8e42c - github.com/devfile/devworkspace-operator v0.15.2 + github.com/devfile/api/v2 v2.0.0-20220928161623-fe7c10eaa530 + github.com/devfile/devworkspace-operator v0.17.0 github.com/go-logr/logr v0.4.0 github.com/golang/mock v1.5.0 github.com/google/go-cmp v0.5.6 diff --git a/go.sum b/go.sum index eea239d8b..79bf2207e 100644 --- a/go.sum +++ b/go.sum @@ -112,10 +112,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= github.com/denisenkom/go-mssqldb v0.0.0-20190204142019-df6d76eb9289/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= -github.com/devfile/api/v2 v2.0.0-20220414122024-32cae1f8e42c h1:yyidoxal8ngJWDxRuVZMNh4PBwqDIzOkTeOagtmRiy0= -github.com/devfile/api/v2 v2.0.0-20220414122024-32cae1f8e42c/go.mod h1:kLX/nW93gigOHXK3NLeJL2fSS/sgEe+OHu8bo3aoOi4= -github.com/devfile/devworkspace-operator v0.15.2 h1:CcLGHtuBOKdwpeYV8Iy7ZwUSgavcMbjuPA9ejupM7BE= -github.com/devfile/devworkspace-operator v0.15.2/go.mod h1:fM3/GhPWEL8JZOEImCnpyxTYEf9dN6PsjzJq+ffcD1k= +github.com/devfile/api/v2 v2.0.0-20220928161623-fe7c10eaa530 h1:pZvf4AZrf/ZwV2AwQnTInlUpns+Wj9JYtPRtBDiFHzk= +github.com/devfile/api/v2 v2.0.0-20220928161623-fe7c10eaa530/go.mod h1:dN7xFrOVG+iPqn4UKGibXLd5oVsdE8XyK9OEb5JL3aI= +github.com/devfile/devworkspace-operator v0.17.0 h1:Ml8ncEQAVf/d+DTttQ76oe/btnFQpicRG/XncdflOZo= +github.com/devfile/devworkspace-operator v0.17.0/go.mod h1:xLELAolfebwROqGSvOWhdC0eH7S+V7iVFzHxtm3Jf2A= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dhui/dktest v0.3.2/go.mod h1:l1/ib23a/CmxAe7yixtrYPc8Iy90Zy2udyaHINM5p58= From e1e7789bbe576422e07f525bfdff217ecbad7491 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Tue, 8 Nov 2022 17:44:54 -0500 Subject: [PATCH 2/5] chore: update vendors Signed-off-by: Andrew Obuchowicz --- .../v1alpha2/component_contribution.go | 21 ++ .../workspaces/v1alpha2/devworkspace_types.go | 7 +- .../v1alpha2/zz_generated.deepcopy.go | 30 +++ .../devworkspaceoperatorconfig_types.go | 32 ++- .../v1alpha1/zz_generated.deepcopy.go | 37 ++- .../solvers/basic_solver.go | 3 +- .../pkg/common/naming.go | 21 +- .../devworkspace-operator/pkg/common/types.go | 24 ++ .../pkg/config/defaults.go | 47 +++- .../pkg/config/migrate.go | 4 +- .../devworkspace-operator/pkg/config/sync.go | 232 ++++++++++++++---- .../pkg/constants/attributes.go | 67 +++++ .../pkg/constants/constants.go | 7 +- .../pkg/infrastructure/cluster.go | 4 + .../pkg/provision/sync/diff.go | 36 ++- .../pkg/provision/sync/sync.go | 4 +- .../pkg/provision/sync/update.go | 18 ++ vendor/modules.txt | 8 +- 18 files changed, 525 insertions(+), 77 deletions(-) create mode 100644 vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_contribution.go create mode 100644 vendor/github.com/devfile/devworkspace-operator/pkg/common/types.go diff --git a/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_contribution.go b/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_contribution.go new file mode 100644 index 000000000..2ed69da19 --- /dev/null +++ b/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_contribution.go @@ -0,0 +1,21 @@ +package v1alpha2 + +import attributes "github.com/devfile/api/v2/pkg/attributes" + +type ComponentContribution struct { + // Mandatory name that allows referencing the component + // from other elements (such as commands) or from an external + // devfile that may reference this component through a parent or a plugin. + // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + // +kubebuilder:validation:MaxLength=63 + Name string `json:"name"` + // Map of implementation-dependant free-form YAML attributes. + // +optional + // +kubebuilder:validation:Type=object + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Schemaless + Attributes attributes.Attributes `json:"attributes,omitempty"` + // Reference to a remote Devfile or DevWorkspace resource to be included + // in the DevWorkspace. + PluginComponent `json:",inline"` +} diff --git a/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/devworkspace_types.go b/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/devworkspace_types.go index c7fe603c5..c8a500a08 100644 --- a/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/devworkspace_types.go +++ b/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/devworkspace_types.go @@ -7,9 +7,10 @@ import ( // DevWorkspaceSpec defines the desired state of DevWorkspace type DevWorkspaceSpec struct { - Started bool `json:"started"` - RoutingClass string `json:"routingClass,omitempty"` - Template DevWorkspaceTemplateSpec `json:"template,omitempty"` + Started bool `json:"started"` + RoutingClass string `json:"routingClass,omitempty"` + Template DevWorkspaceTemplateSpec `json:"template,omitempty"` + Contributions []ComponentContribution `json:"contributions,omitempty"` } // DevWorkspaceStatus defines the observed state of DevWorkspace diff --git a/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go b/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go index 01ac606ac..60ed58638 100644 --- a/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go +++ b/vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go @@ -830,6 +830,29 @@ func (in *Component) DeepCopy() *Component { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentContribution) DeepCopyInto(out *ComponentContribution) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(attributes.Attributes, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + in.PluginComponent.DeepCopyInto(&out.PluginComponent) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentContribution. +func (in *ComponentContribution) DeepCopy() *ComponentContribution { + if in == nil { + return nil + } + out := new(ComponentContribution) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ComponentParentOverride) DeepCopyInto(out *ComponentParentOverride) { *out = *in @@ -1637,6 +1660,13 @@ func (in *DevWorkspaceList) DeepCopyObject() runtime.Object { func (in *DevWorkspaceSpec) DeepCopyInto(out *DevWorkspaceSpec) { *out = *in in.Template.DeepCopyInto(&out.Template) + if in.Contributions != nil { + in, out := &in.Contributions, &out.Contributions + *out = make([]ComponentContribution, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevWorkspaceSpec. diff --git a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go index 6b7b936e0..6d84017c8 100644 --- a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go +++ b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go @@ -16,6 +16,7 @@ package v1alpha1 import ( + dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -78,6 +79,21 @@ type StorageSizes struct { PerWorkspace *resource.Quantity `json:"perWorkspace,omitempty"` } +type ServiceAccountConfig struct { + // ServiceAccountName defines a fixed name to be used for all DevWorkspaces. If set, the DevWorkspace + // Operator will not generate a separate ServiceAccount for each DevWorkspace, and will instead create + // a ServiceAccount with the specified name in each namespace where DevWorkspaces are created. If specified, + // the created ServiceAccount will not be removed when DevWorkspaces are deleted and must be cleaned up manually. + // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + // +kubebuilder:validation:MaxLength=63 + ServiceAccountName string `json:"serviceAccountName,omitempty"` + // Disable creation of DevWorkspace ServiceAccounts by the DevWorkspace Operator. If set to true, the serviceAccountName + // field must also be set. If ServiceAccount creation is disabled, it is assumed that the specified ServiceAccount already + // exists in any namespace where a workspace is created. If a suitable ServiceAccount does not exist, starting DevWorkspaces + // will fail. + DisableCreation *bool `json:"disableCreation,omitempty"` +} + type WorkspaceConfig struct { // ImagePullPolicy defines the imagePullPolicy used for containers in a DevWorkspace // For additional information, see Kubernetes documentation for imagePullPolicy. If @@ -94,6 +110,9 @@ type WorkspaceConfig struct { // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ // +kubebuilder:validation:MaxLength=63 PVCName string `json:"pvcName,omitempty"` + // ServiceAccount defines configuration options for the ServiceAccount used for + // DevWorkspaces. + ServiceAccount *ServiceAccountConfig `json:"serviceAccount,omitempty"` // StorageClassName defines an optional storageClass to use for persistent // volume claims created to support DevWorkspaces StorageClassName *string `json:"storageClassName,omitempty"` @@ -123,10 +142,17 @@ type WorkspaceConfig struct { // but the objects will be left on the cluster). The default value is false. CleanupOnStop *bool `json:"cleanupOnStop,omitempty"` // PodSecurityContext overrides the default PodSecurityContext used for all workspace-related - // pods created by the DevWorkspace Operator when running on Kubernetes. On OpenShift, this - // configuration option is ignored. If set, the entire pod security context is overridden; - // values are not merged. + // pods created by the DevWorkspace Operator. If set, defined values are merged into the default + // configuration PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + // ContainerSecurityContext overrides the default ContainerSecurityContext used for all + // workspace-related containers created by the DevWorkspace Operator. If set, defined + // values are merged into the default configuration + ContainerSecurityContext *corev1.SecurityContext `json:"containerSecurityContext,omitempty"` + // DefaultTemplate defines an optional DevWorkspace Spec Template which gets applied to the workspace + // if the workspace's Template Spec Components are not defined. The DefaultTemplate will overwrite the existing + // Template Spec, with the exception of Projects (if any are defined). + DefaultTemplate *dw.DevWorkspaceTemplateSpecContent `json:"defaultTemplate,omitempty"` } // DevWorkspaceOperatorConfig is the Schema for the devworkspaceoperatorconfigs API diff --git a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go index 6054ffc79..d529f17af 100644 --- a/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,3 @@ -//go:build !ignore_autogenerated // +build !ignore_autogenerated // @@ -21,6 +20,7 @@ package v1alpha1 import ( + "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -478,6 +478,26 @@ func (in *RoutingConfig) DeepCopy() *RoutingConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceAccountConfig) DeepCopyInto(out *ServiceAccountConfig) { + *out = *in + if in.DisableCreation != nil { + in, out := &in.DisableCreation, &out.DisableCreation + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountConfig. +func (in *ServiceAccountConfig) DeepCopy() *ServiceAccountConfig { + if in == nil { + return nil + } + out := new(ServiceAccountConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StorageSizes) DeepCopyInto(out *StorageSizes) { *out = *in @@ -506,6 +526,11 @@ func (in *StorageSizes) DeepCopy() *StorageSizes { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkspaceConfig) DeepCopyInto(out *WorkspaceConfig) { *out = *in + if in.ServiceAccount != nil { + in, out := &in.ServiceAccount, &out.ServiceAccount + *out = new(ServiceAccountConfig) + (*in).DeepCopyInto(*out) + } if in.StorageClassName != nil { in, out := &in.StorageClassName, &out.StorageClassName *out = new(string) @@ -531,6 +556,16 @@ func (in *WorkspaceConfig) DeepCopyInto(out *WorkspaceConfig) { *out = new(v1.PodSecurityContext) (*in).DeepCopyInto(*out) } + if in.ContainerSecurityContext != nil { + in, out := &in.ContainerSecurityContext, &out.ContainerSecurityContext + *out = new(v1.SecurityContext) + (*in).DeepCopyInto(*out) + } + if in.DefaultTemplate != nil { + in, out := &in.DefaultTemplate, &out.DefaultTemplate + *out = new(v1alpha2.DevWorkspaceTemplateSpecContent) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceConfig. diff --git a/vendor/github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting/solvers/basic_solver.go b/vendor/github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting/solvers/basic_solver.go index 23beeccc3..f5e4007f9 100644 --- a/vendor/github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting/solvers/basic_solver.go +++ b/vendor/github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting/solvers/basic_solver.go @@ -57,7 +57,8 @@ func (s *BasicSolver) Finalize(*controllerv1alpha1.DevWorkspaceRouting) error { func (s *BasicSolver) GetSpecObjects(routing *controllerv1alpha1.DevWorkspaceRouting, workspaceMeta DevWorkspaceMetadata) (RoutingObjects, error) { routingObjects := RoutingObjects{} - routingSuffix := config.Routing.ClusterHostSuffix + // TODO: Use workspace-scoped ClusterHostSuffix to allow overriding + routingSuffix := config.GetGlobalConfig().Routing.ClusterHostSuffix if routingSuffix == "" { return routingObjects, &RoutingInvalid{"basic routing requires .config.routing.clusterHostSuffix to be set in operator config"} } diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/common/naming.go b/vendor/github.com/devfile/devworkspace-operator/pkg/common/naming.go index 73aef82ba..853e7a347 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/common/naming.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/common/naming.go @@ -48,8 +48,25 @@ func ServiceName(workspaceId string) string { return fmt.Sprintf("%s-%s", workspaceId, "service") } -func ServiceAccountName(workspaceId string) string { - return fmt.Sprintf("%s-%s", workspaceId, "sa") +func ServiceAccountName(workspace *DevWorkspaceWithConfig) string { + if workspace.Config.Workspace.ServiceAccount.ServiceAccountName != "" { + return workspace.Config.Workspace.ServiceAccount.ServiceAccountName + } + return fmt.Sprintf("%s-%s", workspace.Status.DevWorkspaceId, "sa") +} + +func ServiceAccountLabels(workspace *DevWorkspaceWithConfig) map[string]string { + if workspace.Config.Workspace.ServiceAccount.ServiceAccountName != "" { + // One SA used for multiple workspaces; do not add specific DevWorkspace ID. We still need the + // devworkspace ID label in order to cache the ServiceAccount. + return map[string]string{ + constants.DevWorkspaceIDLabel: "", + } + } + return map[string]string{ + constants.DevWorkspaceIDLabel: workspace.Status.DevWorkspaceId, + constants.DevWorkspaceNameLabel: workspace.Name, + } } func EndpointHostname(routingSuffix, workspaceId, endpointName string, endpointPort int) string { diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/common/types.go b/vendor/github.com/devfile/devworkspace-operator/pkg/common/types.go new file mode 100644 index 000000000..70dbda034 --- /dev/null +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/common/types.go @@ -0,0 +1,24 @@ +// Copyright (c) 2019-2022 Red Hat, Inc. +// 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 common + +import ( + dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" + controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" +) + +type DevWorkspaceWithConfig struct { + *dw.DevWorkspace `json:",inline"` + Config *controllerv1alpha1.OperatorConfiguration `json:"resolvedConfig"` +} diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go b/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go index 7fc374088..44c982fc0 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/config/defaults.go @@ -16,9 +16,13 @@ package config import ( + "fmt" + "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" + "github.com/devfile/devworkspace-operator/pkg/infrastructure" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/utils/pointer" ) // defaultConfig represents the default configuration for the DevWorkspace Operator. @@ -30,28 +34,45 @@ var defaultConfig = &v1alpha1.OperatorConfiguration{ Workspace: &v1alpha1.WorkspaceConfig{ ImagePullPolicy: "Always", PVCName: "claim-devworkspace", + ServiceAccount: &v1alpha1.ServiceAccountConfig{ + DisableCreation: pointer.Bool(false), + }, DefaultStorageSize: &v1alpha1.StorageSizes{ Common: &commonStorageSize, PerWorkspace: &perWorkspaceStorageSize, }, - IdleTimeout: "15m", - ProgressTimeout: "5m", - CleanupOnStop: &boolFalse, - PodSecurityContext: &corev1.PodSecurityContext{ - RunAsUser: &int64UID, - RunAsGroup: &int64GID, - RunAsNonRoot: &boolTrue, - FSGroup: &int64UID, - }, + IdleTimeout: "15m", + ProgressTimeout: "5m", + CleanupOnStop: pointer.BoolPtr(false), + PodSecurityContext: nil, + ContainerSecurityContext: &corev1.SecurityContext{}, + DefaultTemplate: nil, }, } +var defaultKubernetesPodSecurityContext = &corev1.PodSecurityContext{ + RunAsUser: pointer.Int64(1234), + RunAsGroup: pointer.Int64(0), + RunAsNonRoot: pointer.Bool(true), + FSGroup: pointer.Int64(1234), +} + +var defaultOpenShiftPodSecurityContext = &corev1.PodSecurityContext{} + // Necessary variables for setting pointer values var ( - boolTrue = true - boolFalse = false - int64UID = int64(1234) - int64GID = int64(0) commonStorageSize = resource.MustParse("10Gi") perWorkspaceStorageSize = resource.MustParse("5Gi") ) + +func setDefaultPodSecurityContext() error { + if !infrastructure.IsInitialized() { + return fmt.Errorf("can not set default pod security context, infrastructure not detected") + } + if infrastructure.IsOpenShift() { + defaultConfig.Workspace.PodSecurityContext = defaultOpenShiftPodSecurityContext + } else { + defaultConfig.Workspace.PodSecurityContext = defaultKubernetesPodSecurityContext + } + return nil +} diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/config/migrate.go b/vendor/github.com/devfile/devworkspace-operator/pkg/config/migrate.go index 6f54f2066..6ae59f18c 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/config/migrate.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/config/migrate.go @@ -22,6 +22,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" crclient "sigs.k8s.io/controller-runtime/pkg/client" dw "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" @@ -128,8 +129,7 @@ func convertConfigMapToConfigCRD(client crclient.Client) (*dw.DevWorkspaceOperat var experimentalFeatures *bool experimentalFeaturesStr := configmap.ControllerCfg.GetExperimentalFeaturesEnabled() if experimentalFeaturesStr != nil && *experimentalFeaturesStr == "true" { - trueBool := true - experimentalFeatures = &trueBool + experimentalFeatures = pointer.Bool(true) } if !setRoutingConfig && !setWorkspaceConfig && experimentalFeatures == nil { diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go b/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go index fcf6a250b..04e93f8b5 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/config/sync.go @@ -17,19 +17,26 @@ package config import ( "context" + "encoding/json" "fmt" + "reflect" "strings" "sync" + dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/devfile/devworkspace-operator/pkg/config/proxy" routeV1 "github.com/openshift/api/route/v1" + corev1 "k8s.io/api/core/v1" k8sErrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/utils/pointer" ctrl "sigs.k8s.io/controller-runtime" crclient "sigs.k8s.io/controller-runtime/pkg/client" controller "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1" + "github.com/devfile/devworkspace-operator/pkg/constants" "github.com/devfile/devworkspace-operator/pkg/infrastructure" ) @@ -39,26 +46,64 @@ const ( ) var ( - Routing *controller.RoutingConfig - Workspace *controller.WorkspaceConfig internalConfig *controller.OperatorConfiguration configMutex sync.Mutex configNamespace string log = ctrl.Log.WithName("operator-configuration") ) -func SetConfigForTesting(config *controller.OperatorConfiguration) { +func GetGlobalConfig() *controller.OperatorConfiguration { + return internalConfig.DeepCopy() +} + +// ResolveConfigForWorkspace returns the resulting config from merging the global DevWorkspaceOperatorConfig with the +// DevWorkspaceOperatorConfig specified by the optional workspace attribute `controller.devfile.io/devworkspace-config`. +// If the `controller.devfile.io/devworkspace-config` is not set, the global DevWorkspaceOperatorConfig is returned. +// If the `controller.devfile.io/devworkspace-config` attribute is incorrectly set, or the specified DevWorkspaceOperatorConfig +// does not exist on the cluster, an error is returned. +func ResolveConfigForWorkspace(workspace *dw.DevWorkspace, client crclient.Client) (*controller.OperatorConfiguration, error) { + if !workspace.Spec.Template.Attributes.Exists(constants.ExternalDevWorkspaceConfiguration) { + return GetGlobalConfig(), nil + } + + namespacedName := types.NamespacedName{} + err := workspace.Spec.Template.Attributes.GetInto(constants.ExternalDevWorkspaceConfiguration, &namespacedName) + if err != nil { + return nil, fmt.Errorf("failed to read attribute %s in DevWorkspace attributes: %w", constants.ExternalDevWorkspaceConfiguration, err) + } + + if namespacedName.Name == "" { + return nil, fmt.Errorf("'name' must be set for attribute %s in DevWorkspace attributes", constants.ExternalDevWorkspaceConfiguration) + } + + if namespacedName.Namespace == "" { + return nil, fmt.Errorf("'namespace' must be set for attribute %s in DevWorkspace attributes", constants.ExternalDevWorkspaceConfiguration) + } + + externalDWOC := &controller.DevWorkspaceOperatorConfig{} + err = client.Get(context.TODO(), namespacedName, externalDWOC) + if err != nil { + return nil, fmt.Errorf("could not fetch external DWOC with name %s in namespace %s: %w", namespacedName.Name, namespacedName.Namespace, err) + } + return getMergedConfig(externalDWOC.Config, internalConfig), nil +} + +func GetConfigForTesting(customConfig *controller.OperatorConfiguration) *controller.OperatorConfiguration { configMutex.Lock() defer configMutex.Unlock() - internalConfig = defaultConfig.DeepCopy() - mergeConfig(config, internalConfig) - updatePublicConfig() + testConfig := defaultConfig.DeepCopy() + mergeConfig(customConfig, testConfig) + return testConfig } func SetupControllerConfig(client crclient.Client) error { if internalConfig != nil { return fmt.Errorf("internal controller configuration is already set up") } + if err := setDefaultPodSecurityContext(); err != nil { + return err + } + internalConfig = &controller.OperatorConfiguration{} namespace, err := infrastructure.GetNamespace() @@ -93,7 +138,7 @@ func SetupControllerConfig(client crclient.Client) error { defaultConfig.Routing.ProxyConfig = clusterProxy internalConfig.Routing.ProxyConfig = proxy.MergeProxyConfigs(clusterProxy, internalConfig.Routing.ProxyConfig) - updatePublicConfig() + logCurrentConfig() return nil } @@ -119,6 +164,13 @@ func getClusterConfig(namespace string, client crclient.Client) (*controller.Dev return clusterConfig, nil } +func getMergedConfig(from, to *controller.OperatorConfiguration) *controller.OperatorConfiguration { + mergedConfig := to.DeepCopy() + fromCopy := from.DeepCopy() + mergeConfig(fromCopy, mergedConfig) + return mergedConfig +} + func syncConfigFrom(newConfig *controller.DevWorkspaceOperatorConfig) { if newConfig == nil || newConfig.Name != OperatorConfigName || newConfig.Namespace != configNamespace { return @@ -127,19 +179,13 @@ func syncConfigFrom(newConfig *controller.DevWorkspaceOperatorConfig) { defer configMutex.Unlock() internalConfig = defaultConfig.DeepCopy() mergeConfig(newConfig.Config, internalConfig) - updatePublicConfig() + logCurrentConfig() } func restoreDefaultConfig() { configMutex.Lock() defer configMutex.Unlock() internalConfig = defaultConfig.DeepCopy() - updatePublicConfig() -} - -func updatePublicConfig() { - Routing = internalConfig.Routing.DeepCopy() - Workspace = internalConfig.Workspace.DeepCopy() logCurrentConfig() } @@ -222,6 +268,17 @@ func mergeConfig(from, to *controller.OperatorConfiguration) { if from.Workspace.PVCName != "" { to.Workspace.PVCName = from.Workspace.PVCName } + if from.Workspace.ServiceAccount != nil { + if to.Workspace.ServiceAccount == nil { + to.Workspace.ServiceAccount = &controller.ServiceAccountConfig{} + } + if from.Workspace.ServiceAccount.ServiceAccountName != "" { + to.Workspace.ServiceAccount.ServiceAccountName = from.Workspace.ServiceAccount.ServiceAccountName + } + if from.Workspace.ServiceAccount.DisableCreation != nil { + to.Workspace.ServiceAccount.DisableCreation = pointer.BoolPtr(*from.Workspace.ServiceAccount.DisableCreation) + } + } if from.Workspace.ImagePullPolicy != "" { to.Workspace.ImagePullPolicy = from.Workspace.ImagePullPolicy } @@ -238,7 +295,10 @@ func mergeConfig(from, to *controller.OperatorConfiguration) { to.Workspace.CleanupOnStop = from.Workspace.CleanupOnStop } if from.Workspace.PodSecurityContext != nil { - to.Workspace.PodSecurityContext = from.Workspace.PodSecurityContext + to.Workspace.PodSecurityContext = mergePodSecurityContext(to.Workspace.PodSecurityContext, from.Workspace.PodSecurityContext) + } + if from.Workspace.ContainerSecurityContext != nil { + to.Workspace.ContainerSecurityContext = mergeContainerSecurityContext(to.Workspace.ContainerSecurityContext, from.Workspace.ContainerSecurityContext) } if from.Workspace.DefaultStorageSize != nil { if to.Workspace.DefaultStorageSize == nil { @@ -253,57 +313,143 @@ func mergeConfig(from, to *controller.OperatorConfiguration) { to.Workspace.DefaultStorageSize.PerWorkspace = &perWorkspaceSizeCopy } } + if from.Workspace.DefaultTemplate != nil { + templateSpecContentCopy := from.Workspace.DefaultTemplate.DeepCopy() + to.Workspace.DefaultTemplate = templateSpecContentCopy + } } } -// logCurrentConfig formats the current operator configuration as a plain string -func logCurrentConfig() { - if internalConfig == nil { - return +func mergePodSecurityContext(base, patch *corev1.PodSecurityContext) *corev1.PodSecurityContext { + baseBytes, err := json.Marshal(base) + if err != nil { + log.Info("Failed to serialize base pod security context: %s", err) + return base + } + patchBytes, err := json.Marshal(patch) + if err != nil { + log.Info("Failed to serialize configured pod security context: %s", err) + return base + } + patchedBytes, err := strategicpatch.StrategicMergePatch(baseBytes, patchBytes, &corev1.PodSecurityContext{}) + if err != nil { + log.Info("Failed to merge configured pod security context: %s", err) + return base + } + patched := &corev1.PodSecurityContext{} + if err := json.Unmarshal(patchedBytes, patched); err != nil { + log.Info("Failed to deserialize patched pod security context: %s", patched) + return base + } + return patched +} + +func mergeContainerSecurityContext(base, patch *corev1.SecurityContext) *corev1.SecurityContext { + baseBytes, err := json.Marshal(base) + if err != nil { + log.Info("Failed to serialize base container security context: %s", err) + return base + } + patchBytes, err := json.Marshal(patch) + if err != nil { + log.Info("Failed to serialize configured container security context: %s", err) + return base + } + patchedBytes, err := strategicpatch.StrategicMergePatch(baseBytes, patchBytes, &corev1.SecurityContext{}) + if err != nil { + log.Info("Failed to merge configured container security context: %s", err) + return base + } + patched := &corev1.SecurityContext{} + if err := json.Unmarshal(patchedBytes, patched); err != nil { + log.Info("Failed to deserialize patched container security context: %s", patched) + return base + } + return patched +} + +func GetCurrentConfigString(currConfig *controller.OperatorConfiguration) string { + if currConfig == nil { + return "" } + + routing := currConfig.Routing var config []string - if Routing != nil { - if Routing.ClusterHostSuffix != "" && Routing.ClusterHostSuffix != defaultConfig.Routing.ClusterHostSuffix { - config = append(config, fmt.Sprintf("routing.clusterHostSuffix=%s", Routing.ClusterHostSuffix)) + if routing != nil { + if routing.ClusterHostSuffix != "" && routing.ClusterHostSuffix != defaultConfig.Routing.ClusterHostSuffix { + config = append(config, fmt.Sprintf("routing.clusterHostSuffix=%s", routing.ClusterHostSuffix)) } - if Routing.DefaultRoutingClass != defaultConfig.Routing.DefaultRoutingClass { - config = append(config, fmt.Sprintf("routing.defaultRoutingClass=%s", Routing.DefaultRoutingClass)) + if routing.DefaultRoutingClass != defaultConfig.Routing.DefaultRoutingClass { + config = append(config, fmt.Sprintf("routing.defaultRoutingClass=%s", routing.DefaultRoutingClass)) } } - if Workspace != nil { - if Workspace.ImagePullPolicy != defaultConfig.Workspace.ImagePullPolicy { - config = append(config, fmt.Sprintf("workspace.imagePullPolicy=%s", Workspace.ImagePullPolicy)) + workspace := currConfig.Workspace + if workspace != nil { + if workspace.ImagePullPolicy != defaultConfig.Workspace.ImagePullPolicy { + config = append(config, fmt.Sprintf("workspace.imagePullPolicy=%s", workspace.ImagePullPolicy)) + } + if workspace.PVCName != defaultConfig.Workspace.PVCName { + config = append(config, fmt.Sprintf("workspace.pvcName=%s", workspace.PVCName)) } - if Workspace.PVCName != defaultConfig.Workspace.PVCName { - config = append(config, fmt.Sprintf("workspace.pvcName=%s", Workspace.PVCName)) + if workspace.ServiceAccount != nil { + if workspace.ServiceAccount.ServiceAccountName != defaultConfig.Workspace.ServiceAccount.ServiceAccountName { + config = append(config, fmt.Sprintf("workspace.serviceAccount.serviceAccountName=%s", workspace.ServiceAccount.ServiceAccountName)) + } + if workspace.ServiceAccount.DisableCreation != nil && *workspace.ServiceAccount.DisableCreation != *defaultConfig.Workspace.ServiceAccount.DisableCreation { + config = append(config, fmt.Sprintf("workspace.serviceAccount.disableCreation=%t", *workspace.ServiceAccount.DisableCreation)) + } } - if Workspace.StorageClassName != nil && Workspace.StorageClassName != defaultConfig.Workspace.StorageClassName { - config = append(config, fmt.Sprintf("workspace.storageClassName=%s", *Workspace.StorageClassName)) + if workspace.StorageClassName != nil && workspace.StorageClassName != defaultConfig.Workspace.StorageClassName { + config = append(config, fmt.Sprintf("workspace.storageClassName=%s", *workspace.StorageClassName)) } - if Workspace.IdleTimeout != defaultConfig.Workspace.IdleTimeout { - config = append(config, fmt.Sprintf("workspace.idleTimeout=%s", Workspace.IdleTimeout)) + if workspace.IdleTimeout != defaultConfig.Workspace.IdleTimeout { + config = append(config, fmt.Sprintf("workspace.idleTimeout=%s", workspace.IdleTimeout)) } - if Workspace.IgnoredUnrecoverableEvents != nil { + if workspace.ProgressTimeout != "" && workspace.ProgressTimeout != defaultConfig.Workspace.ProgressTimeout { + config = append(config, fmt.Sprintf("workspace.progressTimeout=%s", workspace.ProgressTimeout)) + } + if workspace.IgnoredUnrecoverableEvents != nil { config = append(config, fmt.Sprintf("workspace.ignoredUnrecoverableEvents=%s", - strings.Join(Workspace.IgnoredUnrecoverableEvents, ";"))) + strings.Join(workspace.IgnoredUnrecoverableEvents, ";"))) + } + if workspace.CleanupOnStop != nil && *workspace.CleanupOnStop != *defaultConfig.Workspace.CleanupOnStop { + config = append(config, fmt.Sprintf("workspace.cleanupOnStop=%t", *workspace.CleanupOnStop)) } - if Workspace.DefaultStorageSize != nil { - if Workspace.DefaultStorageSize.Common != nil { - config = append(config, fmt.Sprintf("workspace.defaultStorageSize.common=%s", Workspace.DefaultStorageSize.Common.String())) + if workspace.DefaultStorageSize != nil { + if workspace.DefaultStorageSize.Common != nil && workspace.DefaultStorageSize.Common.String() != defaultConfig.Workspace.DefaultStorageSize.Common.String() { + config = append(config, fmt.Sprintf("workspace.defaultStorageSize.common=%s", workspace.DefaultStorageSize.Common.String())) } - if Workspace.DefaultStorageSize.PerWorkspace != nil { - config = append(config, fmt.Sprintf("workspace.defaultStorageSize.perWorkspace=%s", Workspace.DefaultStorageSize.PerWorkspace.String())) + if workspace.DefaultStorageSize.PerWorkspace != nil && workspace.DefaultStorageSize.PerWorkspace.String() != defaultConfig.Workspace.DefaultStorageSize.PerWorkspace.String() { + config = append(config, fmt.Sprintf("workspace.defaultStorageSize.perWorkspace=%s", workspace.DefaultStorageSize.PerWorkspace.String())) } } + if !reflect.DeepEqual(workspace.PodSecurityContext, defaultConfig.Workspace.PodSecurityContext) { + config = append(config, "workspace.podSecurityContext is set") + } + if !reflect.DeepEqual(workspace.ContainerSecurityContext, defaultConfig.Workspace.ContainerSecurityContext) { + config = append(config, "workspace.containerSecurityContext is set") + } + if workspace.DefaultTemplate != nil { + config = append(config, "workspace.defaultTemplate is set") + } } - if internalConfig.EnableExperimentalFeatures != nil && *internalConfig.EnableExperimentalFeatures { + if currConfig.EnableExperimentalFeatures != nil && *currConfig.EnableExperimentalFeatures { config = append(config, "enableExperimentalFeatures=true") } - if len(config) == 0 { + return "" + } else { + return strings.Join(config, ",") + } +} + +// logCurrentConfig formats the current operator configuration as a plain string +func logCurrentConfig() { + currConfig := GetCurrentConfigString(internalConfig) + if len(currConfig) == 0 { log.Info("Updated config to [(default config)]") } else { - log.Info(fmt.Sprintf("Updated config to [%s]", strings.Join(config, ","))) + log.Info(fmt.Sprintf("Updated config to [%s]", currConfig)) } if internalConfig.Routing.ProxyConfig != nil { diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/constants/attributes.go b/vendor/github.com/devfile/devworkspace-operator/pkg/constants/attributes.go index 71994662f..72879c982 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/constants/attributes.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/constants/attributes.go @@ -28,6 +28,21 @@ const ( // stopped. DevWorkspaceStorageTypeAttribute = "controller.devfile.io/storage-type" + // ExternalDevWorkspaceConfiguration is an attribute that allows for specifying an (optional) external DevWorkspaceOperatorConfig + // which will merged with the internal/global DevWorkspaceOperatorConfig. The DevWorkspaceOperatorConfig resulting from the merge will be used for the workspace. + // The fields which are set in the external DevWorkspaceOperatorConfig will overwrite those existing in the + // internal/global DevWorkspaceOperatorConfig during the merge. + // The structure of the attribute value should contain two strings: name and namespace. + // 'name' specifies the metadata.name of the external operator configuration. + // 'namespace' specifies the metadata.namespace of the external operator configuration . + // For example: + // + // attributes: + // controller.devfile.io/devworkspace-config: + // name: external-dwoc-name + // namespace: some-namespace + ExternalDevWorkspaceConfiguration = "controller.devfile.io/devworkspace-config" + // RuntimeClassNameAttribute is an attribute added to a DevWorkspace to specify a runtimeClassName for container // components in the DevWorkspace (pod.spec.runtimeClassName). If empty, no runtimeClassName is added. RuntimeClassNameAttribute = "controller.devfile.io/runtime-class" @@ -74,4 +89,56 @@ const ( // EndpointURLAttribute is an attribute added to endpoints to denote the endpoint on the cluster that // was created to route to this endpoint EndpointURLAttribute = "controller.devfile.io/endpoint-url" + + // ContainerContributionAttribute defines a container component as a container contribution that should be merged + // into an existing container in the devfile if possible. If no suitable container exists, this component + // is treated as a regular container component + ContainerContributionAttribute = "controller.devfile.io/container-contribution" + + // MergeContributionAttribute defines a container component as a target for merging a container contribution. If + // present on a container component, any container contributions will be merged into that container. If multiple + // container components have the merge-contribution attribute, the first one will be used and all others ignored. + MergeContributionAttribute = "controller.devfile.io/merge-contribution" + + // MergedContributionsAttribute is applied as an attribute onto a component to list the components from the unflattened + // DevWorkspace that have been merged into the current component. The contributions are listed in a comma-separated list. + MergedContributionsAttribute = "controller.devfile.io/merged-contributions" + + // PodOverridesAttribute is an attribute applied to a container component or in global attributes to specify overrides + // for the pod spec used in the main workspace deployment. The format of the field is the same as the Kubernetes + // PodSpec API. Overrides are applied over the default pod template spec used via strategic merge patch. + // + // If this attribute is used multiple times, all overrides are applied in the order they are defined in the DevWorkspace, + // with later values overriding previous ones. Overrides defined in the top-level attributes field are applied last and + // override any overrides from container components. + // + // Example: + // kind: DevWorkspace + // apiVersion: workspace.devfile.io/v1alpha2 + // spec: + // template: + // attributes: + // pod-overrides: + // metadata: + // annotations: + // io.openshift.userns: "true" + // io.kubernetes.cri-o.userns-mode: "auto:size=65536;map-to-root=true" # <-- user namespace + // openshift.io/scc: container-build + // spec: + // runtimeClassName: kata + // schedulerName: stork + PodOverridesAttribute = "pod-overrides" + + // ContainerOverridesAttribute is an attribute applied to a container component to specify arbitrary fields in that + // container. This attribute should only be used to set fields that are not configurable in the container component + // itself. Any values specified in the overrides attribute overwrite fields on the container. + // + // Example: + // components: + // - name: go + // attributes: + // container-overrides: {"resources":{"limits":{"nvidia.com/gpu": "1"}}} + // container: + // image: ... + ContainerOverridesAttribute = "container-overrides" ) diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go b/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go index bca103690..d398019c2 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/constants/constants.go @@ -64,9 +64,12 @@ const ( // Constants describing storage classes supported by the controller - // CommonStorageClassType defines the 'common' storage policy -- one PVC is provisioned per namespace and all devworkspace storage - // is mounted in it on subpaths according to devworkspace ID. + // CommonStorageClassType defines the 'common' storage policy, which is an alias of the 'per-user' storage policy, and operates in the same fashion as the 'per-user' storage policy. + // The 'common' storage policy exists only for legacy compatibility. CommonStorageClassType = "common" + // PerUserStorageClassType defines the 'per-user' storage policy -- one PVC is provisioned per namespace and all devworkspace storage + // is mounted in it on subpaths according to devworkspace ID. + PerUserStorageClassType = "per-user" // AsyncStorageClassType defines the 'asynchronous' storage policy. An rsync sidecar is added to devworkspaces that uses SSH to connect // to a storage deployment that mounts a common PVC for the namespace. AsyncStorageClassType = "async" diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/infrastructure/cluster.go b/vendor/github.com/devfile/devworkspace-operator/pkg/infrastructure/cluster.go index 5a08cd3ac..a5587868c 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/infrastructure/cluster.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/infrastructure/cluster.go @@ -60,6 +60,10 @@ func InitializeForTesting(currentInfrastructure Type) { initialized = true } +func IsInitialized() bool { + return initialized +} + // IsOpenShift returns true if the current cluster is an OpenShift (v4.x) cluster. func IsOpenShift() bool { if !initialized { diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diff.go b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diff.go index 9488d725b..1f09d0674 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diff.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diff.go @@ -27,6 +27,7 @@ import ( networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" crclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -37,7 +38,7 @@ type diffFunc func(spec crclient.Object, cluster crclient.Object) (delete, updat var diffFuncs = map[reflect.Type]diffFunc{ reflect.TypeOf(rbacv1.Role{}): allDiffFuncs(labelsAndAnnotationsDiffFunc, basicDiffFunc(roleDiffOpts)), reflect.TypeOf(rbacv1.RoleBinding{}): allDiffFuncs(labelsAndAnnotationsDiffFunc, basicDiffFunc(rolebindingDiffOpts)), - reflect.TypeOf(corev1.ServiceAccount{}): labelsAndAnnotationsDiffFunc, + reflect.TypeOf(corev1.ServiceAccount{}): allDiffFuncs(labelsAndAnnotationsDiffFunc, ownerrefsDiffFunc), reflect.TypeOf(appsv1.Deployment{}): allDiffFuncs(deploymentDiffFunc, labelsAndAnnotationsDiffFunc, basicDiffFunc(deploymentDiffOpts)), reflect.TypeOf(corev1.ConfigMap{}): allDiffFuncs(labelsAndAnnotationsDiffFunc, basicDiffFunc(configmapDiffOpts)), reflect.TypeOf(corev1.Secret{}): allDiffFuncs(labelsAndAnnotationsDiffFunc, basicDiffFunc(secretDiffOpts)), @@ -73,6 +74,16 @@ func labelsAndAnnotationsDiffFunc(spec, cluster crclient.Object) (delete, update return false, false } +func ownerrefsDiffFunc(spec, cluster crclient.Object) (delete, update bool) { + clusterRefs := cluster.GetOwnerReferences() + for _, ownerref := range spec.GetOwnerReferences() { + if !containsOwnerRef(ownerref, clusterRefs) { + return false, true + } + } + return false, false +} + // allDiffFuncs represents an 'and' condition across specified diffFuncs. Functions are checked in provided order, // returning the result of the first function to require an update/deletion. func allDiffFuncs(funcs ...diffFunc) diffFunc { @@ -135,3 +146,26 @@ func serviceDiffFunc(spec, cluster crclient.Object) (delete, update bool) { } return false, specCopy.Spec.Type != clusterCopy.Spec.Type } + +func containsOwnerRef(toCheck metav1.OwnerReference, listRefs []metav1.OwnerReference) bool { + boolPtrsEqual := func(a, b *bool) bool { + // If either is nil, assume check other is nil or false; otherwise, compare actual values + switch { + case a == nil: + return b == nil || !*b + case b == nil: + return a == nil || !*a + default: + return *a == *b + } + } + for _, ref := range listRefs { + if toCheck.Kind == ref.Kind && + toCheck.Name == ref.Name && + toCheck.UID == ref.UID && + boolPtrsEqual(toCheck.Controller, ref.Controller) { + return true + } + } + return false +} diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go index 94aeb1791..1f1d51e74 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go @@ -82,7 +82,7 @@ func createObjectGeneric(specObj crclient.Object, api ClusterAPI) error { // Need to try to update the object to address an edge case where removing a labelselector // results in the object not being tracked by the controller's cache. return updateObjectGeneric(specObj, nil, api) - case k8sErrors.IsInvalid(err): + case k8sErrors.IsInvalid(err), k8sErrors.IsForbidden(err): return &UnrecoverableSyncError{err} default: return err @@ -108,7 +108,7 @@ func updateObjectGeneric(specObj, clusterObj crclient.Object, api ClusterAPI) er case k8sErrors.IsConflict(err), k8sErrors.IsNotFound(err): // Need to catch IsNotFound here because we attempt to update when creation fails with AlreadyExists return NewNotInSync(specObj, NeedRetryReason) - case k8sErrors.IsInvalid(err): + case k8sErrors.IsInvalid(err), k8sErrors.IsForbidden(err): return &UnrecoverableSyncError{err} default: return err diff --git a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/update.go b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/update.go index ef0edc662..592981327 100644 --- a/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/update.go +++ b/vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/update.go @@ -50,11 +50,29 @@ func serviceUpdateFunc(spec, cluster crclient.Object) (crclient.Object, error) { return specService, nil } +func serviceAccountUpdateFunc(spec, cluster crclient.Object) (crclient.Object, error) { + if cluster == nil { + // May occur if ServiceAccount is not cached by the operator + return spec, nil + } + spec.SetResourceVersion(cluster.GetResourceVersion()) + ownerrefs := spec.GetOwnerReferences() + for _, clusterOwnerref := range cluster.GetOwnerReferences() { + if !containsOwnerRef(clusterOwnerref, ownerrefs) { + ownerrefs = append(ownerrefs, clusterOwnerref) + } + } + spec.SetOwnerReferences(ownerrefs) + return spec, nil +} + func getUpdateFunc(obj crclient.Object) updateFunc { objType := reflect.TypeOf(obj).Elem() switch objType { case reflect.TypeOf(corev1.Service{}): return serviceUpdateFunc + case reflect.TypeOf(corev1.ServiceAccount{}): + return serviceAccountUpdateFunc default: return defaultUpdateFunc } diff --git a/vendor/modules.txt b/vendor/modules.txt index 0fe7e5a87..c1ca7d510 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -30,12 +30,12 @@ github.com/cespare/xxhash/v2 github.com/che-incubator/kubernetes-image-puller-operator/api/v1alpha1 # github.com/davecgh/go-spew v1.1.1 => github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/devfile/api/v2 v2.0.0-20220414122024-32cae1f8e42c +# github.com/devfile/api/v2 v2.0.0-20220928161623-fe7c10eaa530 ## explicit github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2 github.com/devfile/api/v2/pkg/attributes github.com/devfile/api/v2/pkg/devfile -# github.com/devfile/devworkspace-operator v0.15.2 +# github.com/devfile/devworkspace-operator v0.17.0 ## explicit github.com/devfile/devworkspace-operator/apis/controller/v1alpha1 github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting @@ -67,7 +67,7 @@ github.com/golang/groupcache/lru # github.com/golang/mock v1.5.0 => github.com/golang/mock v1.5.0 ## explicit github.com/golang/mock/gomock -# github.com/golang/protobuf v1.4.3 => github.com/golang/protobuf v1.4.3 +# github.com/golang/protobuf v1.5.2 => github.com/golang/protobuf v1.4.3 github.com/golang/protobuf/proto github.com/golang/protobuf/ptypes github.com/golang/protobuf/ptypes/any @@ -296,7 +296,7 @@ google.golang.org/grpc/serviceconfig google.golang.org/grpc/stats google.golang.org/grpc/status google.golang.org/grpc/tap -# google.golang.org/protobuf v1.26.0-rc.1 => google.golang.org/protobuf v1.25.0 +# google.golang.org/protobuf v1.26.0 => google.golang.org/protobuf v1.25.0 google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/protowire google.golang.org/protobuf/internal/descfmt From 15f5872957b66110f400fe64c9e79c94f8945422 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Fri, 21 Oct 2022 12:30:45 -0400 Subject: [PATCH 3/5] feat: configure workspace security context for container builds Fix eclipse/che#21770 Signed-off-by: Andrew Obuchowicz --- pkg/common/constants/constants.go | 15 ++ .../dev_workspace_config.go | 55 ++++--- .../dev_workspace_config_test.go | 144 +++++++++++++++++- 3 files changed, 189 insertions(+), 25 deletions(-) diff --git a/pkg/common/constants/constants.go b/pkg/common/constants/constants.go index 4d717c7b8..747d94086 100644 --- a/pkg/common/constants/constants.go +++ b/pkg/common/constants/constants.go @@ -12,6 +12,11 @@ package constants +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/pointer" +) + const ( // PostgresSQL DefaultPostgresUser = "pgche" @@ -135,4 +140,14 @@ var ( "app": "che", "component": "che-gateway-config", } + + DefaultWorkspaceContainerSecurityContext = corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SETGID", + "SETUID", + }, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(false), + } ) diff --git a/pkg/deploy/dev-workspace-config/dev_workspace_config.go b/pkg/deploy/dev-workspace-config/dev_workspace_config.go index 1247adf5d..b9b8e0831 100644 --- a/pkg/deploy/dev-workspace-config/dev_workspace_config.go +++ b/pkg/deploy/dev-workspace-config/dev_workspace_config.go @@ -54,7 +54,7 @@ func (d *DevWorkspaceConfigReconciler) Reconcile(ctx *chetypes.DeployContext) (r if dwoc.Config == nil { dwoc.Config = &controllerv1alpha1.OperatorConfiguration{} } - err := updateOperatorConfig(ctx.CheCluster.Spec.DevEnvironments.Storage, dwoc.Config) + err := updateOperatorConfig(ctx.CheCluster, dwoc.Config) if err != nil { return reconcile.Result{}, false, err } @@ -71,8 +71,9 @@ func (d *DevWorkspaceConfigReconciler) Finalize(ctx *chetypes.DeployContext) boo return true } -func updateOperatorConfig(storage chev2.WorkspaceStorage, operatorConfig *controllerv1alpha1.OperatorConfiguration) error { +func updateOperatorConfig(cheCluster *chev2.CheCluster, operatorConfig *controllerv1alpha1.OperatorConfiguration) error { var pvc *chev2.PVC + storage := cheCluster.Spec.DevEnvironments.Storage pvcStrategy := utils.GetValue(storage.PvcStrategy, constants.DefaultPvcStorageStrategy) switch pvcStrategy { @@ -88,35 +89,41 @@ func updateOperatorConfig(storage chev2.WorkspaceStorage, operatorConfig *contro } } - if pvc != nil { - if operatorConfig.Workspace == nil { - operatorConfig.Workspace = &controllerv1alpha1.WorkspaceConfig{} - } - return updateWorkspaceConfig(pvc, pvcStrategy == constants.PerWorkspacePVCStorageStrategy, operatorConfig.Workspace) + if operatorConfig.Workspace == nil { + operatorConfig.Workspace = &controllerv1alpha1.WorkspaceConfig{} } - return nil -} -func updateWorkspaceConfig(pvc *chev2.PVC, isPerWorkspacePVCStorageStrategy bool, workspaceConfig *controllerv1alpha1.WorkspaceConfig) error { - if pvc.StorageClass != "" { - workspaceConfig.StorageClassName = &pvc.StorageClass - } + return updateWorkspaceConfig(pvc, pvcStrategy == constants.PerWorkspacePVCStorageStrategy, cheCluster.IsContainerBuildCapabilitiesEnabled(), operatorConfig.Workspace) +} - if pvc.ClaimSize != "" { - if workspaceConfig.DefaultStorageSize == nil { - workspaceConfig.DefaultStorageSize = &controllerv1alpha1.StorageSizes{} +func updateWorkspaceConfig(pvc *chev2.PVC, isPerWorkspacePVCStorageStrategy bool, enabledContainerBuildCapabilities bool, workspaceConfig *controllerv1alpha1.WorkspaceConfig) error { + if pvc != nil { + if pvc.StorageClass != "" { + workspaceConfig.StorageClassName = &pvc.StorageClass } - pvcSize, err := resource.ParseQuantity(pvc.ClaimSize) - if err != nil { - return err + if pvc.ClaimSize != "" { + if workspaceConfig.DefaultStorageSize == nil { + workspaceConfig.DefaultStorageSize = &controllerv1alpha1.StorageSizes{} + } + + pvcSize, err := resource.ParseQuantity(pvc.ClaimSize) + if err != nil { + return err + } + + if isPerWorkspacePVCStorageStrategy { + workspaceConfig.DefaultStorageSize.PerWorkspace = &pvcSize + } else { + workspaceConfig.DefaultStorageSize.Common = &pvcSize + } } + } - if isPerWorkspacePVCStorageStrategy { - workspaceConfig.DefaultStorageSize.PerWorkspace = &pvcSize - } else { - workspaceConfig.DefaultStorageSize.Common = &pvcSize - } + workspaceConfig.ContainerSecurityContext = nil + if enabledContainerBuildCapabilities { + workspaceConfig.ContainerSecurityContext = constants.DefaultWorkspaceContainerSecurityContext.DeepCopy() } + return nil } diff --git a/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go b/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go index 2d01bd847..e012a9747 100644 --- a/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go +++ b/pkg/deploy/dev-workspace-config/dev_workspace_config_test.go @@ -15,6 +15,8 @@ import ( "regexp" "testing" + corev1 "k8s.io/api/core/v1" + "github.com/eclipse-che/che-operator/pkg/common/constants" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/utils/pointer" @@ -85,7 +87,9 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { DevEnvironments: chev2.CheClusterDevEnvironments{}, }, }, - expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{}, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{}, + }, }, { name: "Create DevWorkspaceOperatorConfig with StorageClassName only", @@ -315,6 +319,144 @@ func TestReconcileDevWorkspaceConfigPerUserStorage(t *testing.T) { }, }, }, + { + name: "Create DevWorkspaceOperatorConfig without Pod Security Context if container build disabled", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(true), + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{}, + }, + }, + { + name: "Create DevWorkspaceOperatorConfig with Pod and Container Security Context if container build enabled", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(false), + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + ContainerSecurityContext: &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SETGID", + "SETUID", + }, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(false), + }, + }, + }, + }, + { + name: "Update existing DevWorkspaceOperatorConfig by adding Pod and Container Security Context", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(false), + }, + }, + }, + existedObjects: []runtime.Object{ + &controllerv1alpha1.DevWorkspaceOperatorConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: devWorkspaceConfigName, + Namespace: "eclipse-che", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DevWorkspaceOperatorConfig", + APIVersion: controllerv1alpha1.GroupVersion.String(), + }, + Config: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + }, + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + ContainerSecurityContext: &corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{ + "SETGID", + "SETUID", + }, + }, + AllowPrivilegeEscalation: pointer.BoolPtr(false), + }, + }, + }, + }, + { + name: "Update existing DevWorkspaceOperatorConfig by removing Pod and Container Security Context", + cheCluster: &chev2.CheCluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "eclipse-che", + Name: "eclipse-che", + }, + Spec: chev2.CheClusterSpec{ + DevEnvironments: chev2.CheClusterDevEnvironments{ + DisableContainerBuildCapabilities: pointer.BoolPtr(true), + }, + }, + }, + existedObjects: []runtime.Object{ + &controllerv1alpha1.DevWorkspaceOperatorConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: devWorkspaceConfigName, + Namespace: "eclipse-che", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "DevWorkspaceOperatorConfig", + APIVersion: controllerv1alpha1.GroupVersion.String(), + }, + Config: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + ContainerSecurityContext: &corev1.SecurityContext{}, + }, + }, + }, + }, + expectedOperatorConfig: &controllerv1alpha1.OperatorConfiguration{ + Workspace: &controllerv1alpha1.WorkspaceConfig{ + StorageClassName: pointer.StringPtr("default-storage-class"), + DefaultStorageSize: &controllerv1alpha1.StorageSizes{ + Common: &quantity10Gi, + }, + }, + }, + }, } for _, testCase := range testCases { From 2290022922ce97f6d10857dd28cc1bed61f36c70 Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Tue, 8 Nov 2022 18:13:00 -0500 Subject: [PATCH 4/5] chore: update k8s.io/utils Signed-off-by: Andrew Obuchowicz --- go.mod | 1 - go.sum | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 848555485..4358082de 100644 --- a/go.mod +++ b/go.mod @@ -388,7 +388,6 @@ replace ( k8s.io/klog/v2 => k8s.io/klog/v2 v2.8.0 k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.0.0-20180912235703-14b8d2d93fcb k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20200923105717-7eba4cbaebdf - k8s.io/utils => k8s.io/utils v0.0.0-20201110183641-67b214c5f920 kubernetes/klog => kubernetes/klog v1.0.0 modernc.org/b => modernc.org/b v1.0.0 modernc.org/db => modernc.org/db v1.0.0 diff --git a/go.sum b/go.sum index 79bf2207e..a3a20b404 100644 --- a/go.sum +++ b/go.sum @@ -706,8 +706,10 @@ k8s.io/kube-openapi v0.0.0-20200923105717-7eba4cbaebdf h1:7RCqblb9HTvcWeOYwrt1SV k8s.io/kube-openapi v0.0.0-20200923105717-7eba4cbaebdf/go.mod h1:bfCVj+qXcEaE5SCvzBaqpOySr6tuCcpPKqF6HD8nyCw= k8s.io/kubectl v0.0.0-20201218185502-10b66c3fd14b/go.mod h1:2bE0JLYTRDVKDiTREFsjLAx4R2GvUtL/mGYFXfFFMzY= k8s.io/metrics v0.20.2/go.mod h1:yTck5nl5wt/lIeLcU6g0b8/AKJf2girwe0PQiaM4Mwk= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 h1:DnzUXII7sVg1FJ/4JX6YDRJfLNAC7idRatPwe07suiI= +k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8= modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw= From 825d0484466cc42241e316ac61262b995334961a Mon Sep 17 00:00:00 2001 From: Andrew Obuchowicz Date: Tue, 8 Nov 2022 18:13:14 -0500 Subject: [PATCH 5/5] chore: update vendors Signed-off-by: Andrew Obuchowicz --- vendor/k8s.io/utils/pointer/pointer.go | 156 ++++++++++++++++++++----- vendor/k8s.io/utils/trace/trace.go | 2 +- vendor/modules.txt | 3 +- 3 files changed, 128 insertions(+), 33 deletions(-) diff --git a/vendor/k8s.io/utils/pointer/pointer.go b/vendor/k8s.io/utils/pointer/pointer.go index 0a55a844e..1da6f6664 100644 --- a/vendor/k8s.io/utils/pointer/pointer.go +++ b/vendor/k8s.io/utils/pointer/pointer.go @@ -46,86 +46,182 @@ func AllPtrFieldsNil(obj interface{}) bool { return true } -// Int32Ptr returns a pointer to an int32 -func Int32Ptr(i int32) *int32 { +// Int32 returns a pointer to an int32. +func Int32(i int32) *int32 { return &i } -// Int32PtrDerefOr dereference the int32 ptr and returns it if not nil, -// else returns def. -func Int32PtrDerefOr(ptr *int32, def int32) int32 { +var Int32Ptr = Int32 // for back-compat + +// Int32Deref dereferences the int32 ptr and returns it if not nil, or else +// returns def. +func Int32Deref(ptr *int32, def int32) int32 { if ptr != nil { return *ptr } return def } -// Int64Ptr returns a pointer to an int64 -func Int64Ptr(i int64) *int64 { +var Int32PtrDerefOr = Int32Deref // for back-compat + +// Int32Equal returns true if both arguments are nil or both arguments +// dereference to the same value. +func Int32Equal(a, b *int32) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} + +// Int64 returns a pointer to an int64. +func Int64(i int64) *int64 { return &i } -// Int64PtrDerefOr dereference the int64 ptr and returns it if not nil, -// else returns def. -func Int64PtrDerefOr(ptr *int64, def int64) int64 { +var Int64Ptr = Int64 // for back-compat + +// Int64Deref dereferences the int64 ptr and returns it if not nil, or else +// returns def. +func Int64Deref(ptr *int64, def int64) int64 { if ptr != nil { return *ptr } return def } -// BoolPtr returns a pointer to a bool -func BoolPtr(b bool) *bool { +var Int64PtrDerefOr = Int64Deref // for back-compat + +// Int64Equal returns true if both arguments are nil or both arguments +// dereference to the same value. +func Int64Equal(a, b *int64) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} + +// Bool returns a pointer to a bool. +func Bool(b bool) *bool { return &b } -// BoolPtrDerefOr dereference the bool ptr and returns it if not nil, -// else returns def. -func BoolPtrDerefOr(ptr *bool, def bool) bool { +var BoolPtr = Bool // for back-compat + +// BoolDeref dereferences the bool ptr and returns it if not nil, or else +// returns def. +func BoolDeref(ptr *bool, def bool) bool { if ptr != nil { return *ptr } return def } -// StringPtr returns a pointer to the passed string. -func StringPtr(s string) *string { +var BoolPtrDerefOr = BoolDeref // for back-compat + +// BoolEqual returns true if both arguments are nil or both arguments +// dereference to the same value. +func BoolEqual(a, b *bool) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} + +// String returns a pointer to a string. +func String(s string) *string { return &s } -// StringPtrDerefOr dereference the string ptr and returns it if not nil, -// else returns def. -func StringPtrDerefOr(ptr *string, def string) string { +var StringPtr = String // for back-compat + +// StringDeref dereferences the string ptr and returns it if not nil, or else +// returns def. +func StringDeref(ptr *string, def string) string { if ptr != nil { return *ptr } return def } -// Float32Ptr returns a pointer to the passed float32. -func Float32Ptr(i float32) *float32 { +var StringPtrDerefOr = StringDeref // for back-compat + +// StringEqual returns true if both arguments are nil or both arguments +// dereference to the same value. +func StringEqual(a, b *string) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} + +// Float32 returns a pointer to the a float32. +func Float32(i float32) *float32 { return &i } -// Float32PtrDerefOr dereference the float32 ptr and returns it if not nil, -// else returns def. -func Float32PtrDerefOr(ptr *float32, def float32) float32 { +var Float32Ptr = Float32 + +// Float32Deref dereferences the float32 ptr and returns it if not nil, or else +// returns def. +func Float32Deref(ptr *float32, def float32) float32 { if ptr != nil { return *ptr } return def } -// Float64Ptr returns a pointer to the passed float64. -func Float64Ptr(i float64) *float64 { +var Float32PtrDerefOr = Float32Deref // for back-compat + +// Float32Equal returns true if both arguments are nil or both arguments +// dereference to the same value. +func Float32Equal(a, b *float32) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} + +// Float64 returns a pointer to the a float64. +func Float64(i float64) *float64 { return &i } -// Float64PtrDerefOr dereference the float64 ptr and returns it if not nil, -// else returns def. -func Float64PtrDerefOr(ptr *float64, def float64) float64 { +var Float64Ptr = Float64 + +// Float64Deref dereferences the float64 ptr and returns it if not nil, or else +// returns def. +func Float64Deref(ptr *float64, def float64) float64 { if ptr != nil { return *ptr } return def } + +var Float64PtrDerefOr = Float64Deref // for back-compat + +// Float64Equal returns true if both arguments are nil or both arguments +// dereference to the same value. +func Float64Equal(a, b *float64) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} diff --git a/vendor/k8s.io/utils/trace/trace.go b/vendor/k8s.io/utils/trace/trace.go index 2af4967ca..3023d1066 100644 --- a/vendor/k8s.io/utils/trace/trace.go +++ b/vendor/k8s.io/utils/trace/trace.go @@ -56,7 +56,7 @@ func writeTraceItemSummary(b *bytes.Buffer, msg string, totalTime time.Duration, b.WriteString(" ") } - b.WriteString(fmt.Sprintf("%vms (%v)", durationToMilliseconds(totalTime), startTime.Format("15:04:00.000"))) + b.WriteString(fmt.Sprintf("%vms (%v)", durationToMilliseconds(totalTime), startTime.Format("15:04:05.000"))) } func durationToMilliseconds(timeDuration time.Duration) int64 { diff --git a/vendor/modules.txt b/vendor/modules.txt index c1ca7d510..bd4536eb7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -648,7 +648,7 @@ k8s.io/component-base/config/v1alpha1 k8s.io/klog/v2 # k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 => k8s.io/kube-openapi v0.0.0-20200923105717-7eba4cbaebdf k8s.io/kube-openapi/pkg/util/proto -# k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 => k8s.io/utils v0.0.0-20201110183641-67b214c5f920 +# k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 ## explicit k8s.io/utils/buffer k8s.io/utils/integer @@ -1064,7 +1064,6 @@ sigs.k8s.io/yaml # k8s.io/klog/v2 => k8s.io/klog/v2 v2.8.0 # k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.0.0-20180912235703-14b8d2d93fcb # k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20200923105717-7eba4cbaebdf -# k8s.io/utils => k8s.io/utils v0.0.0-20201110183641-67b214c5f920 # kubernetes/klog => kubernetes/klog v1.0.0 # modernc.org/b => modernc.org/b v1.0.0 # modernc.org/db => modernc.org/db v1.0.0