Sync the certificate from che-git-self-signed-cert to user namespaces (#1222)
feat: Sync the git tls certificate configuration in a format digestable by DWO. Other slightly related changes: * Make sure the version content annotations survive across multiple conversions between v1 and v2alpha1. * Add DWO watch labels so that our stuff is picked up. * irifrance/gini has moved to go-air/ginipull/1249/head
parent
777f2687bf
commit
0e72bb2ca8
|
|
@ -300,7 +300,7 @@
|
|||
| [github.com/golangplus/bytes@45c989fe545070ef7c9003cf1998bb195c61731a](https://github.com/golangplus/bytes.git) | BSD-3-Clause | [clearlydefined](https://clearlydefined.io/definitions/git/github/golangplus/bytes/45c989fe545070ef7c9003cf1998bb195c61731a) |
|
||||
| [github.com/grpc-ecosystem/grpc-health-probe@v0.3.2](https://github.com/grpc-ecosystem/grpc-health-probe.git) | Apache-2.0 | [clearlydefined](https://clearlydefined.io/definitions/git/github/grpc-ecosystem/grpc-health-probe/71ebd03865797e785bdc7ae6fababe548b75188e) |
|
||||
| [github.com/hokaccha/go-prettyjson@108c894c2c0e4a3236172e3698c14f1e3199548d](https://github.com/hokaccha/go-prettyjson.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/hokaccha/go-prettyjson/108c894c2c0e4a3236172e3698c14f1e3199548d) |
|
||||
| [github.com/irifrance/gini@v1.0.1](https://github.com/irifrance/gini.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/irifrance/gini/ab553a98575687dd98cf73371b2fc398f41d10fc) |
|
||||
| [github.com/go-air/gini@v1.0.1](https://github.com/go-air/gini.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/go-air/gini/ab553a98575687dd98cf73371b2fc398f41d10fc) |
|
||||
| [github.com/itchyny/astgen-go@cf3ea398f64584ef328f8fa3e0281536dbaffa4b](https://github.com/itchyny/astgen-go.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/itchyny/astgen-go/cf3ea398f64584ef328f8fa3e0281536dbaffa4b) |
|
||||
| [github.com/itchyny/gojq@v0.11.0](https://github.com/itchyny/gojq.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/itchyny/gojq/d33449f4c07af896f91db06c7b64052c92ebe42b) |
|
||||
| [github.com/jackc/pgmock@13a1b77aafa2641ad31b655a18e8c3605ef55e2d](https://github.com/jackc/pgmock.git) | MIT | [clearlydefined](https://clearlydefined.io/definitions/git/github/jackc/pgmock/13a1b77aafa2641ad31b655a18e8c3605ef55e2d) |
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func V1ToV2alpha1(v1 *v1.CheCluster, v2 *v2alpha1.CheCluster) error {
|
|||
}
|
||||
}
|
||||
|
||||
v2.ObjectMeta = v1.ObjectMeta
|
||||
v2.ObjectMeta = *v1.ObjectMeta.DeepCopy()
|
||||
v2.Spec = v2Spec
|
||||
|
||||
v1Spec, err := yaml.Marshal(v1.Spec)
|
||||
|
|
@ -89,7 +89,7 @@ func V2alpha1ToV1(v2 *v2alpha1.CheCluster, v1Obj *v1.CheCluster) error {
|
|||
}
|
||||
}
|
||||
|
||||
v1Obj.ObjectMeta = v2.ObjectMeta
|
||||
v1Obj.ObjectMeta = *v2.ObjectMeta.DeepCopy()
|
||||
v1Obj.Spec = v1Spec
|
||||
v1Obj.Status = v1.CheClusterStatus{}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/che-incubator/kubernetes-image-puller-operator/api/v1alpha1"
|
||||
v1 "github.com/eclipse-che/che-operator/api/v1"
|
||||
"github.com/eclipse-che/che-operator/api/v2alpha1"
|
||||
|
|
@ -691,17 +693,13 @@ func TestFullCircleV1(t *testing.T) {
|
|||
convertedV1 := v1.CheCluster{}
|
||||
V2alpha1ToV1(&v2Obj, &convertedV1)
|
||||
|
||||
if !reflect.DeepEqual(&v1Obj, &convertedV1) {
|
||||
t.Errorf("V1 not equal to itself after the conversion through v2alpha1: %v", cmp.Diff(&v1Obj, &convertedV1))
|
||||
}
|
||||
assert.Empty(t, convertedV1.Annotations[v1StorageAnnotation])
|
||||
assert.NotEmpty(t, convertedV1.Annotations[v2alpha1StorageAnnotation])
|
||||
|
||||
if convertedV1.Annotations[v1StorageAnnotation] != "" {
|
||||
t.Errorf("The v1 storage annotations should not be present on the v1 object")
|
||||
}
|
||||
// remove v2 content annotation on the convertedV1 so that it doesn't interfere with the equality.
|
||||
delete(convertedV1.Annotations, v2alpha1StorageAnnotation)
|
||||
|
||||
if convertedV1.Annotations[v2alpha1StorageAnnotation] == "" {
|
||||
t.Errorf("The v2alpha1 storage annotation should be present on the v1 object")
|
||||
}
|
||||
assert.Equal(t, &v1Obj, &convertedV1)
|
||||
}
|
||||
|
||||
func TestFullCircleV2(t *testing.T) {
|
||||
|
|
@ -744,17 +742,13 @@ func TestFullCircleV2(t *testing.T) {
|
|||
convertedV2 := v2alpha1.CheCluster{}
|
||||
V1ToV2alpha1(&v1Obj, &convertedV2)
|
||||
|
||||
if !reflect.DeepEqual(&v2Obj, &convertedV2) {
|
||||
t.Errorf("V2alpha1 not equal to itself after the conversion through v1: %v", cmp.Diff(&v2Obj, &convertedV2))
|
||||
}
|
||||
assert.Empty(t, convertedV2.Annotations[v2alpha1StorageAnnotation])
|
||||
assert.NotEmpty(t, convertedV2.Annotations[v1StorageAnnotation])
|
||||
|
||||
if convertedV2.Annotations[v2alpha1StorageAnnotation] != "" {
|
||||
t.Errorf("The v2alpha1 storage annotations should not be present on the v2alpha1 object")
|
||||
}
|
||||
// remove v1 content annotation on the convertedV1 so that it doesn't interfere with the equality.
|
||||
delete(convertedV2.Annotations, v1StorageAnnotation)
|
||||
|
||||
if convertedV2.Annotations[v1StorageAnnotation] == "" {
|
||||
t.Errorf("The v1 storage annotation should be present on the v2alpha1 object")
|
||||
}
|
||||
assert.Equal(t, &v2Obj, &convertedV2)
|
||||
}
|
||||
|
||||
func onFakeOpenShift(f func()) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/deploy/gateway"
|
||||
|
|
@ -672,7 +674,7 @@ func determineEndpointScheme(e dw.Endpoint) string {
|
|||
scheme = string(e.Protocol)
|
||||
}
|
||||
|
||||
upgradeToSecure := e.Secure
|
||||
upgradeToSecure := pointer.BoolPtrDerefOr(e.Secure, false)
|
||||
|
||||
// gateway is always on HTTPS, so if the endpoint is served through the gateway, we need to use the TLS'd variant.
|
||||
if e.Attributes.GetString(urlRewriteSupportedEndpointAttributeName, nil) == "true" {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/utils/pointer"
|
||||
|
||||
"github.com/eclipse-che/che-operator/pkg/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -145,7 +147,7 @@ func subdomainDevWorkspaceRouting() *dwo.DevWorkspaceRouting {
|
|||
Exposure: dw.PublicEndpointExposure,
|
||||
Protocol: "http",
|
||||
Path: "/2.js",
|
||||
Secure: true,
|
||||
Secure: pointer.BoolPtr(true),
|
||||
},
|
||||
{
|
||||
Name: "e3",
|
||||
|
|
@ -186,7 +188,7 @@ func relocatableDevWorkspaceRouting() *dwo.DevWorkspaceRouting {
|
|||
Exposure: dw.PublicEndpointExposure,
|
||||
Protocol: "http",
|
||||
Path: "/2.js",
|
||||
Secure: true,
|
||||
Secure: pointer.BoolPtr(true),
|
||||
Attributes: attributes.Attributes{
|
||||
urlRewriteSupportedEndpointAttributeName: apiext.JSON{Raw: []byte("\"true\"")},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ func (r *CheUserNamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|||
For(obj).
|
||||
Watches(&source.Kind{Type: &corev1.Secret{}}, r.watchRulesForSecrets(ctx)).
|
||||
Watches(&source.Kind{Type: &corev1.ConfigMap{}}, r.watchRulesForConfigMaps(ctx)).
|
||||
Watches(&source.Kind{Type: &v1.CheCluster{}}, r.triggerAllNamespaces(ctx))
|
||||
Watches(&source.Kind{Type: &v1.CheCluster{}}, r.triggerAllNamespaces())
|
||||
|
||||
return bld.Complete(r)
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ func (r *CheUserNamespaceReconciler) isInManagedNamespace(ctx context.Context, o
|
|||
return err == nil && info != nil && info.OwnerUid != ""
|
||||
}
|
||||
|
||||
func (r *CheUserNamespaceReconciler) triggerAllNamespaces(ctx context.Context) handler.EventHandler {
|
||||
func (r *CheUserNamespaceReconciler) triggerAllNamespaces() handler.EventHandler {
|
||||
return handler.EnqueueRequestsFromMapFunc(
|
||||
handler.MapFunc(func(obj client.Object) []reconcile.Request {
|
||||
nss := r.namespaceCache.GetAllKnownNamespaces()
|
||||
|
|
@ -228,6 +228,11 @@ func (r *CheUserNamespaceReconciler) Reconcile(ctx context.Context, req ctrl.Req
|
|||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
if err = r.reconcileGitTlsCertificate(ctx, req.Name, checluster, deployContext); err != nil {
|
||||
logrus.Errorf("Failed to reconcile Che git TLS certificate into namespace '%s': %v", req.Name, err)
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +291,8 @@ func (r *CheUserNamespaceReconciler) reconcileSelfSignedCert(ctx context.Context
|
|||
Name: targetCertName,
|
||||
Namespace: targetNs,
|
||||
Labels: defaults.AddStandardLabelsForComponent(checluster, userSettingsComponentLabelValue, map[string]string{
|
||||
constants.DevWorkspaceMountLabel: "true",
|
||||
constants.DevWorkspaceMountLabel: "true",
|
||||
constants.DevWorkspaceWatchSecretLabel: "true",
|
||||
}),
|
||||
Annotations: map[string]string{
|
||||
constants.DevWorkspaceMountAsAnnotation: "file",
|
||||
|
|
@ -330,7 +336,8 @@ func (r *CheUserNamespaceReconciler) reconcileTrustedCerts(ctx context.Context,
|
|||
Name: targetConfigMapName,
|
||||
Namespace: targetNs,
|
||||
Labels: defaults.AddStandardLabelsForComponent(checluster, userSettingsComponentLabelValue, map[string]string{
|
||||
constants.DevWorkspaceMountLabel: "true",
|
||||
constants.DevWorkspaceMountLabel: "true",
|
||||
constants.DevWorkspaceWatchConfigMapLabel: "true",
|
||||
}),
|
||||
Annotations: addToFirst(sourceMap.Annotations, map[string]string{
|
||||
constants.DevWorkspaceMountAsAnnotation: "file",
|
||||
|
|
@ -397,7 +404,8 @@ func (r *CheUserNamespaceReconciler) reconcileProxySettings(ctx context.Context,
|
|||
}
|
||||
|
||||
requiredLabels := defaults.AddStandardLabelsForComponent(checluster, userSettingsComponentLabelValue, map[string]string{
|
||||
constants.DevWorkspaceMountLabel: "true",
|
||||
constants.DevWorkspaceMountLabel: "true",
|
||||
constants.DevWorkspaceWatchConfigMapLabel: "true",
|
||||
})
|
||||
requiredAnnos := map[string]string{
|
||||
constants.DevWorkspaceMountAsAnnotation: "env",
|
||||
|
|
@ -421,6 +429,50 @@ func (r *CheUserNamespaceReconciler) reconcileProxySettings(ctx context.Context,
|
|||
return err
|
||||
}
|
||||
|
||||
func (r *CheUserNamespaceReconciler) reconcileGitTlsCertificate(ctx context.Context, targetNs string, checluster *v2alpha1.CheCluster, deployContext *deploy.DeployContext) error {
|
||||
targetName := prefixedName(checluster, "git-tls-creds")
|
||||
delConfigMap := func() error {
|
||||
_, err := deploy.Delete(deployContext, client.ObjectKey{Name: targetName, Namespace: targetNs}, &corev1.Secret{})
|
||||
return err
|
||||
}
|
||||
|
||||
clusterv1 := org.AsV1(checluster)
|
||||
if !clusterv1.Spec.Server.GitSelfSignedCert {
|
||||
return delConfigMap()
|
||||
}
|
||||
|
||||
gitCert := &corev1.ConfigMap{}
|
||||
|
||||
if err := deployContext.ClusterAPI.Client.Get(ctx, client.ObjectKey{Name: deploy.GitSelfSignedCertsConfigMapName, Namespace: checluster.Namespace}, gitCert); err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
return delConfigMap()
|
||||
}
|
||||
|
||||
target := corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ConfigMap",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: targetName,
|
||||
Namespace: targetNs,
|
||||
Labels: defaults.AddStandardLabelsForComponent(checluster, userSettingsComponentLabelValue, map[string]string{
|
||||
constants.DevWorkspaceGitTLSLabel: "true",
|
||||
constants.DevWorkspaceWatchConfigMapLabel: "true",
|
||||
}),
|
||||
},
|
||||
Data: map[string]string{
|
||||
"host": gitCert.Data["githost"],
|
||||
"certificate": gitCert.Data["ca.crt"],
|
||||
},
|
||||
}
|
||||
|
||||
_, err := deploy.DoSync(deployContext, &target, deploy.ConfigMapDiffOpts)
|
||||
return err
|
||||
}
|
||||
|
||||
func prefixedName(checluster *v2alpha1.CheCluster, name string) string {
|
||||
return checluster.Name + "-" + checluster.Namespace + "-" + name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ func setupCheCluster(t *testing.T, ctx context.Context, cl client.Client, scheme
|
|||
},
|
||||
Spec: v1.CheClusterSpec{
|
||||
Server: v1.CheClusterSpecServer{
|
||||
CheHost: "che-host",
|
||||
CheHost: "che-host",
|
||||
GitSelfSignedCert: true,
|
||||
CustomCheProperties: map[string]string{
|
||||
"CHE_INFRA_OPENSHIFT_ROUTE_HOST_DOMAIN__SUFFIX": "root-domain",
|
||||
},
|
||||
|
|
@ -106,6 +107,20 @@ func setupCheCluster(t *testing.T, ctx context.Context, cl client.Client, scheme
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gitTlsCredentials := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deploy.GitSelfSignedCertsConfigMapName,
|
||||
Namespace: cheNamespaceName,
|
||||
},
|
||||
Data: map[string]string{
|
||||
"githost": "the.host.of.git",
|
||||
"ca.crt": "the public certificate of the.host.of.git",
|
||||
},
|
||||
}
|
||||
if err := cl.Create(ctx, gitTlsCredentials); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := devworkspace.New(cl, scheme)
|
||||
// the reconciliation needs to run twice for it to be truly finished - we're setting up finalizers etc...
|
||||
if _, err := r.Reconcile(context.TODO(), reconcile.Request{NamespacedName: types.NamespacedName{Name: cheName, Namespace: cheNamespaceName}}); err != nil {
|
||||
|
|
@ -301,6 +316,13 @@ func TestCreatesDataInNamespace(t *testing.T) {
|
|||
assert.Equal(t, 2, len(caCerts.Data), "Expecting exactly 2 data entries in the trusted cert config map")
|
||||
assert.Equal(t, "trusted cert 1", string(caCerts.Data["trusted1"]), "Unexpected trusted cert 1 value")
|
||||
assert.Equal(t, "trusted cert 2", string(caCerts.Data["trusted2"]), "Unexpected trusted cert 2 value")
|
||||
|
||||
gitTlsConfig := corev1.ConfigMap{}
|
||||
assert.NoError(t, cl.Get(ctx, client.ObjectKey{Name: "che-eclipse-che-git-tls-creds", Namespace: namespace.GetName()}, &gitTlsConfig))
|
||||
assert.Equal(t, "true", gitTlsConfig.Labels[constants.DevWorkspaceGitTLSLabel])
|
||||
assert.Equal(t, "true", gitTlsConfig.Labels[constants.DevWorkspaceWatchConfigMapLabel])
|
||||
assert.Equal(t, "the.host.of.git", gitTlsConfig.Data["host"])
|
||||
assert.Equal(t, "the public certificate of the.host.of.git", gitTlsConfig.Data["certificate"])
|
||||
}
|
||||
|
||||
t.Run("k8s", func(t *testing.T) {
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -7,8 +7,8 @@ require (
|
|||
github.com/bitly/go-simplejson v0.0.0-00010101000000-000000000000 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/che-incubator/kubernetes-image-puller-operator v0.0.0-20210929175054-0128446f5af7
|
||||
github.com/devfile/api/v2 v2.0.0-20210713124824-03e023e7078b
|
||||
github.com/devfile/devworkspace-operator v0.2.1-0.20211005102315-728dff7e987c
|
||||
github.com/devfile/api/v2 v2.0.0-20210917193329-089a48011460
|
||||
github.com/devfile/devworkspace-operator v0.2.1-0.20211213140302-4226bdb05e56
|
||||
github.com/go-logr/logr v0.4.0
|
||||
github.com/golang/mock v1.5.0
|
||||
github.com/google/go-cmp v0.5.6
|
||||
|
|
@ -212,7 +212,7 @@ replace (
|
|||
github.com/huandu/xstrings => github.com/huandu/xstrings v1.2.0
|
||||
github.com/imdario/mergo => github.com/imdario/mergo v0.3.5
|
||||
github.com/inconshreveable/mousetrap => github.com/inconshreveable/mousetrap v1.0.0
|
||||
github.com/irifrance/gini => github.com/irifrance/gini v1.0.1
|
||||
github.com/irifrance/gini => github.com/go-air/gini v1.0.1
|
||||
github.com/itchyny/astgen-go => github.com/itchyny/astgen-go v0.0.0-20200519013840-cf3ea398f645
|
||||
github.com/itchyny/go-flags => github.com/itchyny/go-flags v1.5.0
|
||||
github.com/itchyny/gojq => github.com/itchyny/gojq v0.11.0
|
||||
|
|
|
|||
10
go.sum
10
go.sum
|
|
@ -115,10 +115,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-20210713124824-03e023e7078b h1:N00ORHA5iamvPKpDFfSAkAczAaCBvK8l0EzAphsgFSI=
|
||||
github.com/devfile/api/v2 v2.0.0-20210713124824-03e023e7078b/go.mod h1:QNzaIVQnCsYfXed+QZOn1uvEQFzyhvpi/uc3g/b2ws0=
|
||||
github.com/devfile/devworkspace-operator v0.2.1-0.20211005102315-728dff7e987c h1:ua0f1tLDmxUhKPFHbSIxKE/oWB7GHZNhVRoh3V/NStU=
|
||||
github.com/devfile/devworkspace-operator v0.2.1-0.20211005102315-728dff7e987c/go.mod h1:NJBkFTNuP1vusHXm8yky1hjA1JVtRdrWl49vaQs0eiw=
|
||||
github.com/devfile/api/v2 v2.0.0-20210917193329-089a48011460 h1:cmd+3poyUwevcWchYdvE02YT1nQU4SJpA5/wrdLrpWE=
|
||||
github.com/devfile/api/v2 v2.0.0-20210917193329-089a48011460/go.mod h1:kLX/nW93gigOHXK3NLeJL2fSS/sgEe+OHu8bo3aoOi4=
|
||||
github.com/devfile/devworkspace-operator v0.2.1-0.20211213140302-4226bdb05e56 h1:2BDnr7bPGoAs4vCiW5XIwp4M0L9Mecbvm5N48AuNgoc=
|
||||
github.com/devfile/devworkspace-operator v0.2.1-0.20211213140302-4226bdb05e56/go.mod h1:XP3lnHXRIItnXEa4YKyk2ZnEthVQQWjcA219FZs2ZpM=
|
||||
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=
|
||||
|
|
@ -166,6 +166,7 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7
|
|||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/globalsign/mgo v0.0.0-20160323214708-72aab81a5dec/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-air/gini v1.0.1/go.mod h1:swH5OTtiG/X/YrU06r288qZwq6I1agpbuXQOB55xqGU=
|
||||
github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||
|
|
@ -274,7 +275,6 @@ github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
|||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/irifrance/gini v1.0.1/go.mod h1:swH5OTtiG/X/YrU06r288qZwq6I1agpbuXQOB55xqGU=
|
||||
github.com/itchyny/astgen-go v0.0.0-20200519013840-cf3ea398f645/go.mod h1:296z3W7Xsrp2mlIY88ruDKscuvrkL6zXCNRtaYVshzw=
|
||||
github.com/itchyny/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQfWYJ+MNbA=
|
||||
github.com/itchyny/gojq v0.11.0/go.mod h1:my6D2qN2Sm6qa+/5GsPDUZlCWGR+U8Qsa9he76sudv0=
|
||||
|
|
|
|||
|
|
@ -18,14 +18,15 @@ const (
|
|||
)
|
||||
|
||||
// CommandGroupKind describes the kind of command group.
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug;deploy
|
||||
type CommandGroupKind string
|
||||
|
||||
const (
|
||||
BuildCommandGroupKind CommandGroupKind = "build"
|
||||
RunCommandGroupKind CommandGroupKind = "run"
|
||||
TestCommandGroupKind CommandGroupKind = "test"
|
||||
DebugCommandGroupKind CommandGroupKind = "debug"
|
||||
BuildCommandGroupKind CommandGroupKind = "build"
|
||||
RunCommandGroupKind CommandGroupKind = "run"
|
||||
TestCommandGroupKind CommandGroupKind = "test"
|
||||
DebugCommandGroupKind CommandGroupKind = "debug"
|
||||
DeployCommandGroupKind CommandGroupKind = "deploy"
|
||||
)
|
||||
|
||||
type CommandGroup struct {
|
||||
|
|
@ -34,7 +35,7 @@ type CommandGroup struct {
|
|||
|
||||
// +optional
|
||||
// Identifies the default command for a given group kind
|
||||
IsDefault bool `json:"isDefault,omitempty"`
|
||||
IsDefault *bool `json:"isDefault,omitempty"`
|
||||
}
|
||||
|
||||
type BaseCommand struct {
|
||||
|
|
@ -144,7 +145,7 @@ type ExecCommand struct {
|
|||
// If set to `true` the command won't be restarted and it is expected to handle file changes on its own.
|
||||
//
|
||||
// Default value is `false`
|
||||
HotReloadCapable bool `json:"hotReloadCapable,omitempty"`
|
||||
HotReloadCapable *bool `json:"hotReloadCapable,omitempty"`
|
||||
}
|
||||
|
||||
type ApplyCommand struct {
|
||||
|
|
@ -163,7 +164,7 @@ type CompositeCommand struct {
|
|||
|
||||
// Indicates if the sub-commands should be executed concurrently
|
||||
// +optional
|
||||
Parallel bool `json:"parallel,omitempty"`
|
||||
Parallel *bool `json:"parallel,omitempty"`
|
||||
}
|
||||
|
||||
type CustomCommand struct {
|
||||
|
|
|
|||
2
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_container.go
generated
vendored
2
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_container.go
generated
vendored
|
|
@ -69,7 +69,7 @@ type Container struct {
|
|||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
DedicatedPod bool `json:"dedicatedPod,omitempty"`
|
||||
DedicatedPod *bool `json:"dedicatedPod,omitempty"`
|
||||
}
|
||||
|
||||
type EnvVar struct {
|
||||
|
|
|
|||
38
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_image.go
generated
vendored
Normal file
38
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_image.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package v1alpha2
|
||||
|
||||
// ImageType describes the type of image.
|
||||
// Only one of the following image type may be specified.
|
||||
// +kubebuilder:validation:Enum=Dockerfile
|
||||
type ImageType string
|
||||
|
||||
const (
|
||||
DockerfileImageType ImageType = "Dockerfile"
|
||||
)
|
||||
|
||||
type BaseImage struct {
|
||||
}
|
||||
|
||||
// Component that allows the developer to build a runtime image for outerloop
|
||||
type ImageComponent struct {
|
||||
BaseComponent `json:",inline"`
|
||||
Image `json:",inline"`
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
// Name of the image for the resulting outerloop build
|
||||
ImageName string `json:"imageName"`
|
||||
ImageUnion `json:",inline"`
|
||||
}
|
||||
|
||||
// +union
|
||||
type ImageUnion struct {
|
||||
// Type of image
|
||||
//
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
ImageType ImageType `json:"imageType,omitempty"`
|
||||
|
||||
// Allows specifying dockerfile type build
|
||||
// +optional
|
||||
Dockerfile *DockerfileImage `json:"dockerfile,omitempty"`
|
||||
}
|
||||
81
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_image_dockerfile.go
generated
vendored
Normal file
81
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_image_dockerfile.go
generated
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package v1alpha2
|
||||
|
||||
// DockerfileSrcType describes the type of
|
||||
// the src for the Dockerfile outerloop build.
|
||||
// Only one of the following location type may be specified.
|
||||
// +kubebuilder:validation:Enum=Uri;DevfileRegistry;Git
|
||||
type DockerfileSrcType string
|
||||
|
||||
const (
|
||||
UriLikeDockerfileSrcType DockerfileSrcType = "Uri"
|
||||
DevfileRegistryLikeDockerfileSrcType DockerfileSrcType = "DevfileRegistry"
|
||||
GitLikeDockerfileSrcType DockerfileSrcType = "Git"
|
||||
)
|
||||
|
||||
// Dockerfile Image type to specify the outerloop build using a Dockerfile
|
||||
type DockerfileImage struct {
|
||||
BaseImage `json:",inline"`
|
||||
DockerfileSrc `json:",inline"`
|
||||
Dockerfile `json:",inline"`
|
||||
}
|
||||
|
||||
// +union
|
||||
type DockerfileSrc struct {
|
||||
// Type of Dockerfile src
|
||||
// +
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
SrcType DockerfileSrcType `json:"srcType,omitempty"`
|
||||
|
||||
// URI Reference of a Dockerfile.
|
||||
// It can be a full URL or a relative URI from the current devfile as the base URI.
|
||||
// +optional
|
||||
Uri string `json:"uri,omitempty"`
|
||||
|
||||
// Dockerfile's Devfile Registry source
|
||||
// +optional
|
||||
DevfileRegistry *DockerfileDevfileRegistrySource `json:"devfileRegistry,omitempty"`
|
||||
|
||||
// Dockerfile's Git source
|
||||
// +optional
|
||||
Git *DockerfileGitProjectSource `json:"git,omitempty"`
|
||||
}
|
||||
|
||||
type Dockerfile struct {
|
||||
// Path of source directory to establish build context. Defaults to ${PROJECT_ROOT} in the container
|
||||
// +optional
|
||||
BuildContext string `json:"buildContext,omitempty"`
|
||||
|
||||
// The arguments to supply to the dockerfile build.
|
||||
// +optional
|
||||
Args []string `json:"args,omitempty" patchStrategy:"replace"`
|
||||
|
||||
// Specify if a privileged builder pod is required.
|
||||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
RootRequired *bool `json:"rootRequired,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfileDevfileRegistrySource struct {
|
||||
// Id in a devfile registry that contains a Dockerfile. The src in the OCI registry
|
||||
// required for the Dockerfile build will be downloaded for building the image.
|
||||
Id string `json:"id"`
|
||||
|
||||
// Devfile Registry URL to pull the Dockerfile from when using the Devfile Registry as Dockerfile src.
|
||||
// To ensure the Dockerfile gets resolved consistently in different environments,
|
||||
// it is recommended to always specify the `devfileRegistryUrl` when `Id` is used.
|
||||
// +optional
|
||||
RegistryUrl string `json:"registryUrl,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfileGitProjectSource struct {
|
||||
// Git src for the Dockerfile build. The src required for the Dockerfile build will need to be
|
||||
// cloned for building the image.
|
||||
GitProjectSource `json:",inline"`
|
||||
|
||||
// Location of the Dockerfile in the Git repository when using git as Dockerfile src.
|
||||
// Defaults to Dockerfile.
|
||||
// +optional
|
||||
FileLocation string `json:"fileLocation,omitempty"`
|
||||
}
|
||||
2
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_volume.go
generated
vendored
2
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/component_volume.go
generated
vendored
|
|
@ -15,5 +15,5 @@ type Volume struct {
|
|||
// +optional
|
||||
// Ephemeral volumes are not stored persistently across restarts. Defaults
|
||||
// to false
|
||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||
Ephemeral *bool `json:"ephemeral,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
// ComponentType describes the type of component.
|
||||
// Only one of the following component type may be specified.
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Plugin;Custom
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Image;Plugin;Custom
|
||||
type ComponentType string
|
||||
|
||||
const (
|
||||
|
|
@ -16,6 +16,7 @@ const (
|
|||
OpenshiftComponentType ComponentType = "Openshift"
|
||||
PluginComponentType ComponentType = "Plugin"
|
||||
VolumeComponentType ComponentType = "Volume"
|
||||
ImageComponentType ComponentType = "Image"
|
||||
CustomComponentType ComponentType = "Custom"
|
||||
)
|
||||
|
||||
|
|
@ -72,6 +73,10 @@ type ComponentUnion struct {
|
|||
// +optional
|
||||
Volume *VolumeComponent `json:"volume,omitempty"`
|
||||
|
||||
// Allows specifying the definition of an image for outer loop builds
|
||||
// +optional
|
||||
Image *ImageComponent `json:"image,omitempty"`
|
||||
|
||||
// Allows importing a plugin.
|
||||
//
|
||||
// Plugins are mainly imported devfiles that contribute components, commands
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ type DevWorkspaceTemplateSpec struct {
|
|||
|
||||
// +devfile:overrides:generate
|
||||
type DevWorkspaceTemplateSpecContent struct {
|
||||
// Map of key-value variables used for string replacement in the devfile. Values can can be referenced via {{variable-key}}
|
||||
// Map of key-value variables used for string replacement in the devfile. Values can be referenced via {{variable-key}}
|
||||
// to replace the corresponding value in string fields in the devfile. Replacement cannot be used for
|
||||
//
|
||||
// - schemaVersion, metadata, parent source
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ type Endpoint struct {
|
|||
// Describes whether the endpoint should be secured and protected by some
|
||||
// authentication process. This requires a protocol of `https` or `wss`.
|
||||
// +optional
|
||||
Secure bool `json:"secure,omitempty"`
|
||||
Secure *bool `json:"secure,omitempty"`
|
||||
|
||||
// Path of the endpoint URL
|
||||
// +optional
|
||||
|
|
|
|||
2
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/import_reference.go
generated
vendored
2
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/import_reference.go
generated
vendored
|
|
@ -47,7 +47,7 @@ type ImportReference struct {
|
|||
|
||||
// Registry URL to pull the parent devfile from when using id in the parent reference.
|
||||
// To ensure the parent devfile gets resolved consistently in different environments,
|
||||
// it is recommended to always specify the `regsitryURL` when `Id` is used.
|
||||
// it is recommended to always specify the `registryUrl` when `id` is used.
|
||||
// +optional
|
||||
RegistryUrl string `json:"registryUrl,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@ type GitLikeProjectSource struct {
|
|||
// +optional
|
||||
CheckoutFrom *CheckoutFrom `json:"checkoutFrom,omitempty"`
|
||||
|
||||
// The remotes map which should be initialized in the git project. Must have at least one remote configured
|
||||
// The remotes map which should be initialized in the git project.
|
||||
// Projects must have at least one remote configured while StarterProjects & Image Component's Git source can only have at most one remote configured.
|
||||
Remotes map[string]string `json:"remotes"`
|
||||
}
|
||||
|
||||
|
|
|
|||
980
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go
generated
vendored
980
vendor/github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2/zz_generated.deepcopy.go
generated
vendored
File diff suppressed because it is too large
Load Diff
|
|
@ -142,7 +142,7 @@ type CommandParentOverride struct {
|
|||
// +union
|
||||
type ComponentUnionParentOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Plugin
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Image;Plugin
|
||||
// Type of component
|
||||
//
|
||||
// +unionDiscriminator
|
||||
|
|
@ -172,6 +172,10 @@ type ComponentUnionParentOverride struct {
|
|||
// +optional
|
||||
Volume *VolumeComponentParentOverride `json:"volume,omitempty"`
|
||||
|
||||
// Allows specifying the definition of an image for outer loop builds
|
||||
// +optional
|
||||
Image *ImageComponentParentOverride `json:"image,omitempty"`
|
||||
|
||||
// Allows importing a plugin.
|
||||
//
|
||||
// Plugins are mainly imported devfiles that contribute components, commands
|
||||
|
|
@ -262,6 +266,12 @@ type VolumeComponentParentOverride struct {
|
|||
VolumeParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
// Component that allows the developer to build a runtime image for outerloop
|
||||
type ImageComponentParentOverride struct {
|
||||
BaseComponentParentOverride `json:",inline"`
|
||||
ImageParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type PluginComponentParentOverride struct {
|
||||
BaseComponentParentOverride `json:",inline"`
|
||||
ImportReferenceParentOverride `json:",inline"`
|
||||
|
|
@ -330,7 +340,7 @@ type ExecCommandParentOverride struct {
|
|||
// If set to `true` the command won't be restarted and it is expected to handle file changes on its own.
|
||||
//
|
||||
// Default value is `false`
|
||||
HotReloadCapable bool `json:"hotReloadCapable,omitempty"`
|
||||
HotReloadCapable *bool `json:"hotReloadCapable,omitempty"`
|
||||
}
|
||||
|
||||
type ApplyCommandParentOverride struct {
|
||||
|
|
@ -350,7 +360,7 @@ type CompositeCommandParentOverride struct {
|
|||
|
||||
// Indicates if the sub-commands should be executed concurrently
|
||||
// +optional
|
||||
Parallel bool `json:"parallel,omitempty"`
|
||||
Parallel *bool `json:"parallel,omitempty"`
|
||||
}
|
||||
|
||||
// DevWorkspace component: Anything that will bring additional features / tooling / behaviour / context
|
||||
|
|
@ -420,7 +430,7 @@ type ContainerParentOverride struct {
|
|||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
DedicatedPod bool `json:"dedicatedPod,omitempty"`
|
||||
DedicatedPod *bool `json:"dedicatedPod,omitempty"`
|
||||
}
|
||||
|
||||
type EndpointParentOverride struct {
|
||||
|
|
@ -471,7 +481,7 @@ type EndpointParentOverride struct {
|
|||
// Describes whether the endpoint should be secured and protected by some
|
||||
// authentication process. This requires a protocol of `https` or `wss`.
|
||||
// +optional
|
||||
Secure bool `json:"secure,omitempty"`
|
||||
Secure *bool `json:"secure,omitempty"`
|
||||
|
||||
// Path of the endpoint URL
|
||||
// +optional
|
||||
|
|
@ -507,7 +517,15 @@ type VolumeParentOverride struct {
|
|||
// +optional
|
||||
// Ephemeral volumes are not stored persistently across restarts. Defaults
|
||||
// to false
|
||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||
Ephemeral *bool `json:"ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
type ImageParentOverride struct {
|
||||
|
||||
// +optional
|
||||
// Name of the image for the resulting outerloop build
|
||||
ImageName string `json:"imageName,omitempty"`
|
||||
ImageUnionParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type ImportReferenceParentOverride struct {
|
||||
|
|
@ -515,7 +533,7 @@ type ImportReferenceParentOverride struct {
|
|||
|
||||
// Registry URL to pull the parent devfile from when using id in the parent reference.
|
||||
// To ensure the parent devfile gets resolved consistently in different environments,
|
||||
// it is recommended to always specify the `regsitryURL` when `Id` is used.
|
||||
// it is recommended to always specify the `registryUrl` when `id` is used.
|
||||
// +optional
|
||||
RegistryUrl string `json:"registryUrl,omitempty"`
|
||||
}
|
||||
|
|
@ -548,7 +566,8 @@ type GitLikeProjectSourceParentOverride struct {
|
|||
CheckoutFrom *CheckoutFromParentOverride `json:"checkoutFrom,omitempty"`
|
||||
|
||||
// +optional
|
||||
// The remotes map which should be initialized in the git project. Must have at least one remote configured
|
||||
// The remotes map which should be initialized in the git project.
|
||||
// Projects must have at least one remote configured while StarterProjects & Image Component's Git source can only have at most one remote configured.
|
||||
Remotes map[string]string `json:"remotes,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -615,6 +634,21 @@ type K8sLikeComponentLocationParentOverride struct {
|
|||
Inlined string `json:"inlined,omitempty"`
|
||||
}
|
||||
|
||||
// +union
|
||||
type ImageUnionParentOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Dockerfile
|
||||
// Type of image
|
||||
//
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
ImageType ImageTypeParentOverride `json:"imageType,omitempty"`
|
||||
|
||||
// Allows specifying dockerfile type build
|
||||
// +optional
|
||||
Dockerfile *DockerfileImageParentOverride `json:"dockerfile,omitempty"`
|
||||
}
|
||||
|
||||
// Location from where the an import reference is retrieved
|
||||
// +union
|
||||
type ImportReferenceUnionParentOverride struct {
|
||||
|
|
@ -705,6 +739,17 @@ type BaseCommandParentOverride struct {
|
|||
// Only one of the following component type may be specified.
|
||||
type K8sLikeComponentLocationTypeParentOverride string
|
||||
|
||||
// ImageType describes the type of image.
|
||||
// Only one of the following image type may be specified.
|
||||
type ImageTypeParentOverride string
|
||||
|
||||
// Dockerfile Image type to specify the outerloop build using a Dockerfile
|
||||
type DockerfileImageParentOverride struct {
|
||||
BaseImageParentOverride `json:",inline"`
|
||||
DockerfileSrcParentOverride `json:",inline"`
|
||||
DockerfileParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
// ImportReferenceType describes the type of location
|
||||
// from where the referenced template structure should be retrieved.
|
||||
// Only one of the following parent locations may be specified.
|
||||
|
|
@ -721,7 +766,7 @@ type KubernetesCustomResourceImportReferenceParentOverride struct {
|
|||
// +union
|
||||
type ComponentUnionPluginOverrideParentOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Image
|
||||
// Type of component
|
||||
//
|
||||
// +unionDiscriminator
|
||||
|
|
@ -750,6 +795,10 @@ type ComponentUnionPluginOverrideParentOverride struct {
|
|||
// shared by several other components
|
||||
// +optional
|
||||
Volume *VolumeComponentPluginOverrideParentOverride `json:"volume,omitempty"`
|
||||
|
||||
// Allows specifying the definition of an image for outer loop builds
|
||||
// +optional
|
||||
Image *ImageComponentPluginOverrideParentOverride `json:"image,omitempty"`
|
||||
}
|
||||
|
||||
// +union
|
||||
|
|
@ -793,7 +842,51 @@ type CommandGroupParentOverride struct {
|
|||
|
||||
// +optional
|
||||
// Identifies the default command for a given group kind
|
||||
IsDefault bool `json:"isDefault,omitempty"`
|
||||
IsDefault *bool `json:"isDefault,omitempty"`
|
||||
}
|
||||
|
||||
type BaseImageParentOverride struct {
|
||||
}
|
||||
|
||||
// +union
|
||||
type DockerfileSrcParentOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Uri;DevfileRegistry;Git
|
||||
// Type of Dockerfile src
|
||||
// +
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
SrcType DockerfileSrcTypeParentOverride `json:"srcType,omitempty"`
|
||||
|
||||
// URI Reference of a Dockerfile.
|
||||
// It can be a full URL or a relative URI from the current devfile as the base URI.
|
||||
// +optional
|
||||
Uri string `json:"uri,omitempty"`
|
||||
|
||||
// Dockerfile's Devfile Registry source
|
||||
// +optional
|
||||
DevfileRegistry *DockerfileDevfileRegistrySourceParentOverride `json:"devfileRegistry,omitempty"`
|
||||
|
||||
// Dockerfile's Git source
|
||||
// +optional
|
||||
Git *DockerfileGitProjectSourceParentOverride `json:"git,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfileParentOverride struct {
|
||||
|
||||
// Path of source directory to establish build context. Defaults to ${PROJECT_ROOT} in the container
|
||||
// +optional
|
||||
BuildContext string `json:"buildContext,omitempty"`
|
||||
|
||||
// The arguments to supply to the dockerfile build.
|
||||
// +optional
|
||||
Args []string `json:"args,omitempty" patchStrategy:"replace"`
|
||||
|
||||
// Specify if a privileged builder pod is required.
|
||||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
RootRequired *bool `json:"rootRequired,omitempty"`
|
||||
}
|
||||
|
||||
// ComponentType describes the type of component.
|
||||
|
|
@ -823,6 +916,12 @@ type VolumeComponentPluginOverrideParentOverride struct {
|
|||
VolumePluginOverrideParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
// Component that allows the developer to build a runtime image for outerloop
|
||||
type ImageComponentPluginOverrideParentOverride struct {
|
||||
BaseComponentPluginOverrideParentOverride `json:",inline"`
|
||||
ImagePluginOverrideParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
// CommandType describes the type of command.
|
||||
// Only one of the following command type may be specified.
|
||||
type CommandTypePluginOverrideParentOverride string
|
||||
|
|
@ -867,7 +966,7 @@ type ExecCommandPluginOverrideParentOverride struct {
|
|||
// If set to `true` the command won't be restarted and it is expected to handle file changes on its own.
|
||||
//
|
||||
// Default value is `false`
|
||||
HotReloadCapable bool `json:"hotReloadCapable,omitempty"`
|
||||
HotReloadCapable *bool `json:"hotReloadCapable,omitempty"`
|
||||
}
|
||||
|
||||
type ApplyCommandPluginOverrideParentOverride struct {
|
||||
|
|
@ -887,13 +986,44 @@ type CompositeCommandPluginOverrideParentOverride struct {
|
|||
|
||||
// Indicates if the sub-commands should be executed concurrently
|
||||
// +optional
|
||||
Parallel bool `json:"parallel,omitempty"`
|
||||
Parallel *bool `json:"parallel,omitempty"`
|
||||
}
|
||||
|
||||
// CommandGroupKind describes the kind of command group.
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug;deploy
|
||||
type CommandGroupKindParentOverride string
|
||||
|
||||
// DockerfileSrcType describes the type of
|
||||
// the src for the Dockerfile outerloop build.
|
||||
// Only one of the following location type may be specified.
|
||||
type DockerfileSrcTypeParentOverride string
|
||||
|
||||
type DockerfileDevfileRegistrySourceParentOverride struct {
|
||||
|
||||
// +optional
|
||||
// Id in a devfile registry that contains a Dockerfile. The src in the OCI registry
|
||||
// required for the Dockerfile build will be downloaded for building the image.
|
||||
Id string `json:"id,omitempty"`
|
||||
|
||||
// Devfile Registry URL to pull the Dockerfile from when using the Devfile Registry as Dockerfile src.
|
||||
// To ensure the Dockerfile gets resolved consistently in different environments,
|
||||
// it is recommended to always specify the `devfileRegistryUrl` when `Id` is used.
|
||||
// +optional
|
||||
RegistryUrl string `json:"registryUrl,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfileGitProjectSourceParentOverride struct {
|
||||
|
||||
// Git src for the Dockerfile build. The src required for the Dockerfile build will need to be
|
||||
// cloned for building the image.
|
||||
GitProjectSourceParentOverride `json:",inline"`
|
||||
|
||||
// Location of the Dockerfile in the Git repository when using git as Dockerfile src.
|
||||
// Defaults to Dockerfile.
|
||||
// +optional
|
||||
FileLocation string `json:"fileLocation,omitempty"`
|
||||
}
|
||||
|
||||
// DevWorkspace component: Anything that will bring additional features / tooling / behaviour / context
|
||||
// to the devworkspace, in order to make working in it easier.
|
||||
type BaseComponentPluginOverrideParentOverride struct {
|
||||
|
|
@ -962,7 +1092,7 @@ type ContainerPluginOverrideParentOverride struct {
|
|||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
DedicatedPod bool `json:"dedicatedPod,omitempty"`
|
||||
DedicatedPod *bool `json:"dedicatedPod,omitempty"`
|
||||
}
|
||||
|
||||
type EndpointPluginOverrideParentOverride struct {
|
||||
|
|
@ -1013,7 +1143,7 @@ type EndpointPluginOverrideParentOverride struct {
|
|||
// Describes whether the endpoint should be secured and protected by some
|
||||
// authentication process. This requires a protocol of `https` or `wss`.
|
||||
// +optional
|
||||
Secure bool `json:"secure,omitempty"`
|
||||
Secure *bool `json:"secure,omitempty"`
|
||||
|
||||
// Path of the endpoint URL
|
||||
// +optional
|
||||
|
|
@ -1049,7 +1179,15 @@ type VolumePluginOverrideParentOverride struct {
|
|||
// +optional
|
||||
// Ephemeral volumes are not stored persistently across restarts. Defaults
|
||||
// to false
|
||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||
Ephemeral *bool `json:"ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePluginOverrideParentOverride struct {
|
||||
|
||||
// +optional
|
||||
// Name of the image for the resulting outerloop build
|
||||
ImageName string `json:"imageName,omitempty"`
|
||||
ImageUnionPluginOverrideParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type LabeledCommandPluginOverrideParentOverride struct {
|
||||
|
|
@ -1113,6 +1251,21 @@ type K8sLikeComponentLocationPluginOverrideParentOverride struct {
|
|||
Inlined string `json:"inlined,omitempty"`
|
||||
}
|
||||
|
||||
// +union
|
||||
type ImageUnionPluginOverrideParentOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Dockerfile
|
||||
// Type of image
|
||||
//
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
ImageType ImageTypePluginOverrideParentOverride `json:"imageType,omitempty"`
|
||||
|
||||
// Allows specifying dockerfile type build
|
||||
// +optional
|
||||
Dockerfile *DockerfileImagePluginOverrideParentOverride `json:"dockerfile,omitempty"`
|
||||
}
|
||||
|
||||
type BaseCommandPluginOverrideParentOverride struct {
|
||||
|
||||
// +optional
|
||||
|
|
@ -1125,6 +1278,17 @@ type BaseCommandPluginOverrideParentOverride struct {
|
|||
// Only one of the following component type may be specified.
|
||||
type K8sLikeComponentLocationTypePluginOverrideParentOverride string
|
||||
|
||||
// ImageType describes the type of image.
|
||||
// Only one of the following image type may be specified.
|
||||
type ImageTypePluginOverrideParentOverride string
|
||||
|
||||
// Dockerfile Image type to specify the outerloop build using a Dockerfile
|
||||
type DockerfileImagePluginOverrideParentOverride struct {
|
||||
BaseImagePluginOverrideParentOverride `json:",inline"`
|
||||
DockerfileSrcPluginOverrideParentOverride `json:",inline"`
|
||||
DockerfilePluginOverrideParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type CommandGroupPluginOverrideParentOverride struct {
|
||||
|
||||
// +optional
|
||||
|
|
@ -1133,11 +1297,118 @@ type CommandGroupPluginOverrideParentOverride struct {
|
|||
|
||||
// +optional
|
||||
// Identifies the default command for a given group kind
|
||||
IsDefault bool `json:"isDefault,omitempty"`
|
||||
IsDefault *bool `json:"isDefault,omitempty"`
|
||||
}
|
||||
|
||||
type BaseImagePluginOverrideParentOverride struct {
|
||||
}
|
||||
|
||||
// +union
|
||||
type DockerfileSrcPluginOverrideParentOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Uri;DevfileRegistry;Git
|
||||
// Type of Dockerfile src
|
||||
// +
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
SrcType DockerfileSrcTypePluginOverrideParentOverride `json:"srcType,omitempty"`
|
||||
|
||||
// URI Reference of a Dockerfile.
|
||||
// It can be a full URL or a relative URI from the current devfile as the base URI.
|
||||
// +optional
|
||||
Uri string `json:"uri,omitempty"`
|
||||
|
||||
// Dockerfile's Devfile Registry source
|
||||
// +optional
|
||||
DevfileRegistry *DockerfileDevfileRegistrySourcePluginOverrideParentOverride `json:"devfileRegistry,omitempty"`
|
||||
|
||||
// Dockerfile's Git source
|
||||
// +optional
|
||||
Git *DockerfileGitProjectSourcePluginOverrideParentOverride `json:"git,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfilePluginOverrideParentOverride struct {
|
||||
|
||||
// Path of source directory to establish build context. Defaults to ${PROJECT_ROOT} in the container
|
||||
// +optional
|
||||
BuildContext string `json:"buildContext,omitempty"`
|
||||
|
||||
// The arguments to supply to the dockerfile build.
|
||||
// +optional
|
||||
Args []string `json:"args,omitempty" patchStrategy:"replace"`
|
||||
|
||||
// Specify if a privileged builder pod is required.
|
||||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
RootRequired *bool `json:"rootRequired,omitempty"`
|
||||
}
|
||||
|
||||
// CommandGroupKind describes the kind of command group.
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug;deploy
|
||||
type CommandGroupKindPluginOverrideParentOverride string
|
||||
|
||||
// DockerfileSrcType describes the type of
|
||||
// the src for the Dockerfile outerloop build.
|
||||
// Only one of the following location type may be specified.
|
||||
type DockerfileSrcTypePluginOverrideParentOverride string
|
||||
|
||||
type DockerfileDevfileRegistrySourcePluginOverrideParentOverride struct {
|
||||
|
||||
// +optional
|
||||
// Id in a devfile registry that contains a Dockerfile. The src in the OCI registry
|
||||
// required for the Dockerfile build will be downloaded for building the image.
|
||||
Id string `json:"id,omitempty"`
|
||||
|
||||
// Devfile Registry URL to pull the Dockerfile from when using the Devfile Registry as Dockerfile src.
|
||||
// To ensure the Dockerfile gets resolved consistently in different environments,
|
||||
// it is recommended to always specify the `devfileRegistryUrl` when `Id` is used.
|
||||
// +optional
|
||||
RegistryUrl string `json:"registryUrl,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfileGitProjectSourcePluginOverrideParentOverride struct {
|
||||
|
||||
// Git src for the Dockerfile build. The src required for the Dockerfile build will need to be
|
||||
// cloned for building the image.
|
||||
GitProjectSourcePluginOverrideParentOverride `json:",inline"`
|
||||
|
||||
// Location of the Dockerfile in the Git repository when using git as Dockerfile src.
|
||||
// Defaults to Dockerfile.
|
||||
// +optional
|
||||
FileLocation string `json:"fileLocation,omitempty"`
|
||||
}
|
||||
|
||||
type GitProjectSourcePluginOverrideParentOverride struct {
|
||||
GitLikeProjectSourcePluginOverrideParentOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type GitLikeProjectSourcePluginOverrideParentOverride struct {
|
||||
CommonProjectSourcePluginOverrideParentOverride `json:",inline"`
|
||||
|
||||
// Defines from what the project should be checked out. Required if there are more than one remote configured
|
||||
// +optional
|
||||
CheckoutFrom *CheckoutFromPluginOverrideParentOverride `json:"checkoutFrom,omitempty"`
|
||||
|
||||
// +optional
|
||||
// The remotes map which should be initialized in the git project.
|
||||
// Projects must have at least one remote configured while StarterProjects & Image Component's Git source can only have at most one remote configured.
|
||||
Remotes map[string]string `json:"remotes,omitempty"`
|
||||
}
|
||||
|
||||
type CommonProjectSourcePluginOverrideParentOverride struct {
|
||||
}
|
||||
|
||||
type CheckoutFromPluginOverrideParentOverride struct {
|
||||
|
||||
// The revision to checkout from. Should be branch name, tag or commit id.
|
||||
// Default branch is used if missing or specified revision is not found.
|
||||
// +optional
|
||||
Revision string `json:"revision,omitempty"`
|
||||
|
||||
// The remote name should be used as init. Required if there are more than one remote configured
|
||||
// +optional
|
||||
Remote string `json:"remote,omitempty"`
|
||||
}
|
||||
|
||||
func (overrides ParentOverrides) isOverride() {}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ type CommandPluginOverride struct {
|
|||
// +union
|
||||
type ComponentUnionPluginOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume
|
||||
// +kubebuilder:validation:Enum=Container;Kubernetes;Openshift;Volume;Image
|
||||
// Type of component
|
||||
//
|
||||
// +unionDiscriminator
|
||||
|
|
@ -94,6 +94,10 @@ type ComponentUnionPluginOverride struct {
|
|||
// shared by several other components
|
||||
// +optional
|
||||
Volume *VolumeComponentPluginOverride `json:"volume,omitempty"`
|
||||
|
||||
// Allows specifying the definition of an image for outer loop builds
|
||||
// +optional
|
||||
Image *ImageComponentPluginOverride `json:"image,omitempty"`
|
||||
}
|
||||
|
||||
// +union
|
||||
|
|
@ -156,6 +160,12 @@ type VolumeComponentPluginOverride struct {
|
|||
VolumePluginOverride `json:",inline"`
|
||||
}
|
||||
|
||||
// Component that allows the developer to build a runtime image for outerloop
|
||||
type ImageComponentPluginOverride struct {
|
||||
BaseComponentPluginOverride `json:",inline"`
|
||||
ImagePluginOverride `json:",inline"`
|
||||
}
|
||||
|
||||
// CommandType describes the type of command.
|
||||
// Only one of the following command type may be specified.
|
||||
type CommandTypePluginOverride string
|
||||
|
|
@ -200,7 +210,7 @@ type ExecCommandPluginOverride struct {
|
|||
// If set to `true` the command won't be restarted and it is expected to handle file changes on its own.
|
||||
//
|
||||
// Default value is `false`
|
||||
HotReloadCapable bool `json:"hotReloadCapable,omitempty"`
|
||||
HotReloadCapable *bool `json:"hotReloadCapable,omitempty"`
|
||||
}
|
||||
|
||||
type ApplyCommandPluginOverride struct {
|
||||
|
|
@ -220,7 +230,7 @@ type CompositeCommandPluginOverride struct {
|
|||
|
||||
// Indicates if the sub-commands should be executed concurrently
|
||||
// +optional
|
||||
Parallel bool `json:"parallel,omitempty"`
|
||||
Parallel *bool `json:"parallel,omitempty"`
|
||||
}
|
||||
|
||||
// DevWorkspace component: Anything that will bring additional features / tooling / behaviour / context
|
||||
|
|
@ -290,7 +300,7 @@ type ContainerPluginOverride struct {
|
|||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
DedicatedPod bool `json:"dedicatedPod,omitempty"`
|
||||
DedicatedPod *bool `json:"dedicatedPod,omitempty"`
|
||||
}
|
||||
|
||||
type EndpointPluginOverride struct {
|
||||
|
|
@ -341,7 +351,7 @@ type EndpointPluginOverride struct {
|
|||
// Describes whether the endpoint should be secured and protected by some
|
||||
// authentication process. This requires a protocol of `https` or `wss`.
|
||||
// +optional
|
||||
Secure bool `json:"secure,omitempty"`
|
||||
Secure *bool `json:"secure,omitempty"`
|
||||
|
||||
// Path of the endpoint URL
|
||||
// +optional
|
||||
|
|
@ -377,7 +387,15 @@ type VolumePluginOverride struct {
|
|||
// +optional
|
||||
// Ephemeral volumes are not stored persistently across restarts. Defaults
|
||||
// to false
|
||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||
Ephemeral *bool `json:"ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
type ImagePluginOverride struct {
|
||||
|
||||
// +optional
|
||||
// Name of the image for the resulting outerloop build
|
||||
ImageName string `json:"imageName,omitempty"`
|
||||
ImageUnionPluginOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type LabeledCommandPluginOverride struct {
|
||||
|
|
@ -440,6 +458,21 @@ type K8sLikeComponentLocationPluginOverride struct {
|
|||
Inlined string `json:"inlined,omitempty"`
|
||||
}
|
||||
|
||||
// +union
|
||||
type ImageUnionPluginOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Dockerfile
|
||||
// Type of image
|
||||
//
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
ImageType ImageTypePluginOverride `json:"imageType,omitempty"`
|
||||
|
||||
// Allows specifying dockerfile type build
|
||||
// +optional
|
||||
Dockerfile *DockerfileImagePluginOverride `json:"dockerfile,omitempty"`
|
||||
}
|
||||
|
||||
type BaseCommandPluginOverride struct {
|
||||
|
||||
// +optional
|
||||
|
|
@ -452,6 +485,17 @@ type BaseCommandPluginOverride struct {
|
|||
// Only one of the following component type may be specified.
|
||||
type K8sLikeComponentLocationTypePluginOverride string
|
||||
|
||||
// ImageType describes the type of image.
|
||||
// Only one of the following image type may be specified.
|
||||
type ImageTypePluginOverride string
|
||||
|
||||
// Dockerfile Image type to specify the outerloop build using a Dockerfile
|
||||
type DockerfileImagePluginOverride struct {
|
||||
BaseImagePluginOverride `json:",inline"`
|
||||
DockerfileSrcPluginOverride `json:",inline"`
|
||||
DockerfilePluginOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type CommandGroupPluginOverride struct {
|
||||
|
||||
// +optional
|
||||
|
|
@ -460,11 +504,118 @@ type CommandGroupPluginOverride struct {
|
|||
|
||||
// +optional
|
||||
// Identifies the default command for a given group kind
|
||||
IsDefault bool `json:"isDefault,omitempty"`
|
||||
IsDefault *bool `json:"isDefault,omitempty"`
|
||||
}
|
||||
|
||||
type BaseImagePluginOverride struct {
|
||||
}
|
||||
|
||||
// +union
|
||||
type DockerfileSrcPluginOverride struct {
|
||||
|
||||
// +kubebuilder:validation:Enum=Uri;DevfileRegistry;Git
|
||||
// Type of Dockerfile src
|
||||
// +
|
||||
// +unionDiscriminator
|
||||
// +optional
|
||||
SrcType DockerfileSrcTypePluginOverride `json:"srcType,omitempty"`
|
||||
|
||||
// URI Reference of a Dockerfile.
|
||||
// It can be a full URL or a relative URI from the current devfile as the base URI.
|
||||
// +optional
|
||||
Uri string `json:"uri,omitempty"`
|
||||
|
||||
// Dockerfile's Devfile Registry source
|
||||
// +optional
|
||||
DevfileRegistry *DockerfileDevfileRegistrySourcePluginOverride `json:"devfileRegistry,omitempty"`
|
||||
|
||||
// Dockerfile's Git source
|
||||
// +optional
|
||||
Git *DockerfileGitProjectSourcePluginOverride `json:"git,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfilePluginOverride struct {
|
||||
|
||||
// Path of source directory to establish build context. Defaults to ${PROJECT_ROOT} in the container
|
||||
// +optional
|
||||
BuildContext string `json:"buildContext,omitempty"`
|
||||
|
||||
// The arguments to supply to the dockerfile build.
|
||||
// +optional
|
||||
Args []string `json:"args,omitempty" patchStrategy:"replace"`
|
||||
|
||||
// Specify if a privileged builder pod is required.
|
||||
//
|
||||
// Default value is `false`
|
||||
// +optional
|
||||
RootRequired *bool `json:"rootRequired,omitempty"`
|
||||
}
|
||||
|
||||
// CommandGroupKind describes the kind of command group.
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug
|
||||
// +kubebuilder:validation:Enum=build;run;test;debug;deploy
|
||||
type CommandGroupKindPluginOverride string
|
||||
|
||||
// DockerfileSrcType describes the type of
|
||||
// the src for the Dockerfile outerloop build.
|
||||
// Only one of the following location type may be specified.
|
||||
type DockerfileSrcTypePluginOverride string
|
||||
|
||||
type DockerfileDevfileRegistrySourcePluginOverride struct {
|
||||
|
||||
// +optional
|
||||
// Id in a devfile registry that contains a Dockerfile. The src in the OCI registry
|
||||
// required for the Dockerfile build will be downloaded for building the image.
|
||||
Id string `json:"id,omitempty"`
|
||||
|
||||
// Devfile Registry URL to pull the Dockerfile from when using the Devfile Registry as Dockerfile src.
|
||||
// To ensure the Dockerfile gets resolved consistently in different environments,
|
||||
// it is recommended to always specify the `devfileRegistryUrl` when `Id` is used.
|
||||
// +optional
|
||||
RegistryUrl string `json:"registryUrl,omitempty"`
|
||||
}
|
||||
|
||||
type DockerfileGitProjectSourcePluginOverride struct {
|
||||
|
||||
// Git src for the Dockerfile build. The src required for the Dockerfile build will need to be
|
||||
// cloned for building the image.
|
||||
GitProjectSourcePluginOverride `json:",inline"`
|
||||
|
||||
// Location of the Dockerfile in the Git repository when using git as Dockerfile src.
|
||||
// Defaults to Dockerfile.
|
||||
// +optional
|
||||
FileLocation string `json:"fileLocation,omitempty"`
|
||||
}
|
||||
|
||||
type GitProjectSourcePluginOverride struct {
|
||||
GitLikeProjectSourcePluginOverride `json:",inline"`
|
||||
}
|
||||
|
||||
type GitLikeProjectSourcePluginOverride struct {
|
||||
CommonProjectSourcePluginOverride `json:",inline"`
|
||||
|
||||
// Defines from what the project should be checked out. Required if there are more than one remote configured
|
||||
// +optional
|
||||
CheckoutFrom *CheckoutFromPluginOverride `json:"checkoutFrom,omitempty"`
|
||||
|
||||
// +optional
|
||||
// The remotes map which should be initialized in the git project.
|
||||
// Projects must have at least one remote configured while StarterProjects & Image Component's Git source can only have at most one remote configured.
|
||||
Remotes map[string]string `json:"remotes,omitempty"`
|
||||
}
|
||||
|
||||
type CommonProjectSourcePluginOverride struct {
|
||||
}
|
||||
|
||||
type CheckoutFromPluginOverride struct {
|
||||
|
||||
// The revision to checkout from. Should be branch name, tag or commit id.
|
||||
// Default branch is used if missing or specified revision is not found.
|
||||
// +optional
|
||||
Revision string `json:"revision,omitempty"`
|
||||
|
||||
// The remote name should be used as init. Required if there are more than one remote configured
|
||||
// +optional
|
||||
Remote string `json:"remote,omitempty"`
|
||||
}
|
||||
|
||||
func (overrides PluginOverrides) isOverride() {}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,48 @@ type CommandUnionVisitor struct {
|
|||
Custom func(*CustomCommand) error
|
||||
}
|
||||
|
||||
var imageUnion reflect.Type = reflect.TypeOf(ImageUnionVisitor{})
|
||||
|
||||
func (union ImageUnion) Visit(visitor ImageUnionVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *ImageUnion) discriminator() *string {
|
||||
return (*string)(&union.ImageType)
|
||||
}
|
||||
func (union *ImageUnion) Normalize() error {
|
||||
return normalizeUnion(union, imageUnion)
|
||||
}
|
||||
func (union *ImageUnion) Simplify() {
|
||||
simplifyUnion(union, imageUnion)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ImageUnionVisitor struct {
|
||||
Dockerfile func(*DockerfileImage) error
|
||||
}
|
||||
|
||||
var dockerfileSrc reflect.Type = reflect.TypeOf(DockerfileSrcVisitor{})
|
||||
|
||||
func (union DockerfileSrc) Visit(visitor DockerfileSrcVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *DockerfileSrc) discriminator() *string {
|
||||
return (*string)(&union.SrcType)
|
||||
}
|
||||
func (union *DockerfileSrc) Normalize() error {
|
||||
return normalizeUnion(union, dockerfileSrc)
|
||||
}
|
||||
func (union *DockerfileSrc) Simplify() {
|
||||
simplifyUnion(union, dockerfileSrc)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type DockerfileSrcVisitor struct {
|
||||
Uri func(string) error
|
||||
DevfileRegistry func(*DockerfileDevfileRegistrySource) error
|
||||
Git func(*DockerfileGitProjectSource) error
|
||||
}
|
||||
|
||||
var k8sLikeComponentLocation reflect.Type = reflect.TypeOf(K8sLikeComponentLocationVisitor{})
|
||||
|
||||
func (union K8sLikeComponentLocation) Visit(visitor K8sLikeComponentLocationVisitor) error {
|
||||
|
|
@ -69,6 +111,7 @@ type ComponentUnionVisitor struct {
|
|||
Kubernetes func(*KubernetesComponent) error
|
||||
Openshift func(*OpenshiftComponent) error
|
||||
Volume func(*VolumeComponent) error
|
||||
Image func(*ImageComponent) error
|
||||
Plugin func(*PluginComponent) error
|
||||
Custom func(*CustomComponent) error
|
||||
}
|
||||
|
|
@ -138,6 +181,7 @@ type ComponentUnionParentOverrideVisitor struct {
|
|||
Kubernetes func(*KubernetesComponentParentOverride) error
|
||||
Openshift func(*OpenshiftComponentParentOverride) error
|
||||
Volume func(*VolumeComponentParentOverride) error
|
||||
Image func(*ImageComponentParentOverride) error
|
||||
Plugin func(*PluginComponentParentOverride) error
|
||||
}
|
||||
|
||||
|
|
@ -205,6 +249,26 @@ type K8sLikeComponentLocationParentOverrideVisitor struct {
|
|||
Inlined func(string) error
|
||||
}
|
||||
|
||||
var imageUnionParentOverride reflect.Type = reflect.TypeOf(ImageUnionParentOverrideVisitor{})
|
||||
|
||||
func (union ImageUnionParentOverride) Visit(visitor ImageUnionParentOverrideVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *ImageUnionParentOverride) discriminator() *string {
|
||||
return (*string)(&union.ImageType)
|
||||
}
|
||||
func (union *ImageUnionParentOverride) Normalize() error {
|
||||
return normalizeUnion(union, imageUnionParentOverride)
|
||||
}
|
||||
func (union *ImageUnionParentOverride) Simplify() {
|
||||
simplifyUnion(union, imageUnionParentOverride)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ImageUnionParentOverrideVisitor struct {
|
||||
Dockerfile func(*DockerfileImageParentOverride) error
|
||||
}
|
||||
|
||||
var importReferenceUnionParentOverride reflect.Type = reflect.TypeOf(ImportReferenceUnionParentOverrideVisitor{})
|
||||
|
||||
func (union ImportReferenceUnionParentOverride) Visit(visitor ImportReferenceUnionParentOverrideVisitor) error {
|
||||
|
|
@ -248,6 +312,7 @@ type ComponentUnionPluginOverrideParentOverrideVisitor struct {
|
|||
Kubernetes func(*KubernetesComponentPluginOverrideParentOverride) error
|
||||
Openshift func(*OpenshiftComponentPluginOverrideParentOverride) error
|
||||
Volume func(*VolumeComponentPluginOverrideParentOverride) error
|
||||
Image func(*ImageComponentPluginOverrideParentOverride) error
|
||||
}
|
||||
|
||||
var commandUnionPluginOverrideParentOverride reflect.Type = reflect.TypeOf(CommandUnionPluginOverrideParentOverrideVisitor{})
|
||||
|
|
@ -272,6 +337,28 @@ type CommandUnionPluginOverrideParentOverrideVisitor struct {
|
|||
Composite func(*CompositeCommandPluginOverrideParentOverride) error
|
||||
}
|
||||
|
||||
var dockerfileSrcParentOverride reflect.Type = reflect.TypeOf(DockerfileSrcParentOverrideVisitor{})
|
||||
|
||||
func (union DockerfileSrcParentOverride) Visit(visitor DockerfileSrcParentOverrideVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *DockerfileSrcParentOverride) discriminator() *string {
|
||||
return (*string)(&union.SrcType)
|
||||
}
|
||||
func (union *DockerfileSrcParentOverride) Normalize() error {
|
||||
return normalizeUnion(union, dockerfileSrcParentOverride)
|
||||
}
|
||||
func (union *DockerfileSrcParentOverride) Simplify() {
|
||||
simplifyUnion(union, dockerfileSrcParentOverride)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type DockerfileSrcParentOverrideVisitor struct {
|
||||
Uri func(string) error
|
||||
DevfileRegistry func(*DockerfileDevfileRegistrySourceParentOverride) error
|
||||
Git func(*DockerfileGitProjectSourceParentOverride) error
|
||||
}
|
||||
|
||||
var k8sLikeComponentLocationPluginOverrideParentOverride reflect.Type = reflect.TypeOf(K8sLikeComponentLocationPluginOverrideParentOverrideVisitor{})
|
||||
|
||||
func (union K8sLikeComponentLocationPluginOverrideParentOverride) Visit(visitor K8sLikeComponentLocationPluginOverrideParentOverrideVisitor) error {
|
||||
|
|
@ -293,6 +380,48 @@ type K8sLikeComponentLocationPluginOverrideParentOverrideVisitor struct {
|
|||
Inlined func(string) error
|
||||
}
|
||||
|
||||
var imageUnionPluginOverrideParentOverride reflect.Type = reflect.TypeOf(ImageUnionPluginOverrideParentOverrideVisitor{})
|
||||
|
||||
func (union ImageUnionPluginOverrideParentOverride) Visit(visitor ImageUnionPluginOverrideParentOverrideVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *ImageUnionPluginOverrideParentOverride) discriminator() *string {
|
||||
return (*string)(&union.ImageType)
|
||||
}
|
||||
func (union *ImageUnionPluginOverrideParentOverride) Normalize() error {
|
||||
return normalizeUnion(union, imageUnionPluginOverrideParentOverride)
|
||||
}
|
||||
func (union *ImageUnionPluginOverrideParentOverride) Simplify() {
|
||||
simplifyUnion(union, imageUnionPluginOverrideParentOverride)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ImageUnionPluginOverrideParentOverrideVisitor struct {
|
||||
Dockerfile func(*DockerfileImagePluginOverrideParentOverride) error
|
||||
}
|
||||
|
||||
var dockerfileSrcPluginOverrideParentOverride reflect.Type = reflect.TypeOf(DockerfileSrcPluginOverrideParentOverrideVisitor{})
|
||||
|
||||
func (union DockerfileSrcPluginOverrideParentOverride) Visit(visitor DockerfileSrcPluginOverrideParentOverrideVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *DockerfileSrcPluginOverrideParentOverride) discriminator() *string {
|
||||
return (*string)(&union.SrcType)
|
||||
}
|
||||
func (union *DockerfileSrcPluginOverrideParentOverride) Normalize() error {
|
||||
return normalizeUnion(union, dockerfileSrcPluginOverrideParentOverride)
|
||||
}
|
||||
func (union *DockerfileSrcPluginOverrideParentOverride) Simplify() {
|
||||
simplifyUnion(union, dockerfileSrcPluginOverrideParentOverride)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type DockerfileSrcPluginOverrideParentOverrideVisitor struct {
|
||||
Uri func(string) error
|
||||
DevfileRegistry func(*DockerfileDevfileRegistrySourcePluginOverrideParentOverride) error
|
||||
Git func(*DockerfileGitProjectSourcePluginOverrideParentOverride) error
|
||||
}
|
||||
|
||||
var componentUnionPluginOverride reflect.Type = reflect.TypeOf(ComponentUnionPluginOverrideVisitor{})
|
||||
|
||||
func (union ComponentUnionPluginOverride) Visit(visitor ComponentUnionPluginOverrideVisitor) error {
|
||||
|
|
@ -314,6 +443,7 @@ type ComponentUnionPluginOverrideVisitor struct {
|
|||
Kubernetes func(*KubernetesComponentPluginOverride) error
|
||||
Openshift func(*OpenshiftComponentPluginOverride) error
|
||||
Volume func(*VolumeComponentPluginOverride) error
|
||||
Image func(*ImageComponentPluginOverride) error
|
||||
}
|
||||
|
||||
var commandUnionPluginOverride reflect.Type = reflect.TypeOf(CommandUnionPluginOverrideVisitor{})
|
||||
|
|
@ -358,3 +488,45 @@ type K8sLikeComponentLocationPluginOverrideVisitor struct {
|
|||
Uri func(string) error
|
||||
Inlined func(string) error
|
||||
}
|
||||
|
||||
var imageUnionPluginOverride reflect.Type = reflect.TypeOf(ImageUnionPluginOverrideVisitor{})
|
||||
|
||||
func (union ImageUnionPluginOverride) Visit(visitor ImageUnionPluginOverrideVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *ImageUnionPluginOverride) discriminator() *string {
|
||||
return (*string)(&union.ImageType)
|
||||
}
|
||||
func (union *ImageUnionPluginOverride) Normalize() error {
|
||||
return normalizeUnion(union, imageUnionPluginOverride)
|
||||
}
|
||||
func (union *ImageUnionPluginOverride) Simplify() {
|
||||
simplifyUnion(union, imageUnionPluginOverride)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ImageUnionPluginOverrideVisitor struct {
|
||||
Dockerfile func(*DockerfileImagePluginOverride) error
|
||||
}
|
||||
|
||||
var dockerfileSrcPluginOverride reflect.Type = reflect.TypeOf(DockerfileSrcPluginOverrideVisitor{})
|
||||
|
||||
func (union DockerfileSrcPluginOverride) Visit(visitor DockerfileSrcPluginOverrideVisitor) error {
|
||||
return visitUnion(union, visitor)
|
||||
}
|
||||
func (union *DockerfileSrcPluginOverride) discriminator() *string {
|
||||
return (*string)(&union.SrcType)
|
||||
}
|
||||
func (union *DockerfileSrcPluginOverride) Normalize() error {
|
||||
return normalizeUnion(union, dockerfileSrcPluginOverride)
|
||||
}
|
||||
func (union *DockerfileSrcPluginOverride) Simplify() {
|
||||
simplifyUnion(union, dockerfileSrcPluginOverride)
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=false
|
||||
type DockerfileSrcPluginOverrideVisitor struct {
|
||||
Uri func(string) error
|
||||
DevfileRegistry func(*DockerfileDevfileRegistrySourcePluginOverride) error
|
||||
Git func(*DockerfileGitProjectSourcePluginOverride) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,4 +81,12 @@ type DevfileMetadata struct {
|
|||
// Optional devfile website
|
||||
// +optional
|
||||
Website string `json:"website,omitempty"`
|
||||
|
||||
// Optional devfile provider information
|
||||
// +optional
|
||||
Provider string `json:"provider,omitempty"`
|
||||
|
||||
// Optional link to a page that provides support information
|
||||
// +optional
|
||||
SupportUrl string `json:"supportUrl,omitempty"`
|
||||
}
|
||||
|
|
|
|||
1
vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/common.go
generated
vendored
1
vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/common.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import v1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
1
vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devfile.go
generated
vendored
1
vendor/github.com/devfile/devworkspace-operator/apis/controller/v1alpha1/devfile.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type EndpointAttribute string
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package devworkspacerouting
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package devworkspacerouting
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,11 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package solvers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
"github.com/devfile/devworkspace-operator/pkg/config"
|
||||
"github.com/devfile/devworkspace-operator/pkg/constants"
|
||||
|
|
@ -60,7 +59,7 @@ func (s *BasicSolver) GetSpecObjects(routing *controllerv1alpha1.DevWorkspaceRou
|
|||
|
||||
routingSuffix := config.Routing.ClusterHostSuffix
|
||||
if routingSuffix == "" {
|
||||
return routingObjects, errors.New("basic routing requires .config.routing.clusterHostSuffix to be set in operator config")
|
||||
return routingObjects, &RoutingInvalid{"basic routing requires .config.routing.clusterHostSuffix to be set in operator config"}
|
||||
}
|
||||
|
||||
spec := routing.Spec
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package solvers
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package solvers
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package solvers
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package solvers
|
||||
|
||||
import (
|
||||
|
|
@ -76,7 +77,7 @@ func resolveURLForEndpoint(
|
|||
|
||||
func getURLForEndpoint(endpoint dw.Endpoint, host, basePath string, secure bool) string {
|
||||
protocol := endpoint.Protocol
|
||||
if secure && endpoint.Secure {
|
||||
if secure && endpoint.Secure != nil && *endpoint.Secure {
|
||||
protocol = dw.EndpointProtocol(getSecureProtocol(string(protocol)))
|
||||
}
|
||||
var p string
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package solvers
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package devworkspacerouting
|
||||
|
||||
import (
|
||||
|
|
@ -19,22 +20,15 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/pkg/constants"
|
||||
"github.com/devfile/devworkspace-operator/pkg/provision/sync"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
)
|
||||
|
||||
var ingressDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(networkingv1.Ingress{}, "TypeMeta", "ObjectMeta", "Status"),
|
||||
cmpopts.IgnoreFields(networkingv1.HTTPIngressPath{}, "PathType"),
|
||||
}
|
||||
|
||||
func (r *DevWorkspaceRoutingReconciler) syncIngresses(routing *controllerv1alpha1.DevWorkspaceRouting, specIngresses []networkingv1.Ingress) (ok bool, clusterIngresses []networkingv1.Ingress, err error) {
|
||||
ingressesInSync := true
|
||||
|
||||
|
|
@ -52,32 +46,31 @@ func (r *DevWorkspaceRoutingReconciler) syncIngresses(routing *controllerv1alpha
|
|||
ingressesInSync = false
|
||||
}
|
||||
|
||||
for _, specIngress := range specIngresses {
|
||||
if contains, idx := listContainsIngressByName(specIngress, clusterIngresses); contains {
|
||||
clusterIngress := clusterIngresses[idx]
|
||||
if !cmp.Equal(specIngress, clusterIngress, ingressDiffOpts) {
|
||||
r.Log.Info(fmt.Sprintf("Updating ingress: %s", clusterIngress.Name))
|
||||
if r.DebugLogging {
|
||||
r.Log.Info(fmt.Sprintf("Diff: %s", cmp.Diff(specIngress, clusterIngress, ingressDiffOpts)))
|
||||
}
|
||||
// Update ingress's spec
|
||||
clusterIngress.Spec = specIngress.Spec
|
||||
err := r.Update(context.TODO(), &clusterIngress)
|
||||
if err != nil && !errors.IsConflict(err) {
|
||||
return false, nil, err
|
||||
}
|
||||
ingressesInSync = false
|
||||
}
|
||||
} else {
|
||||
err := r.Create(context.TODO(), &specIngress)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
ingressesInSync = false
|
||||
}
|
||||
clusterAPI := sync.ClusterAPI{
|
||||
Client: r.Client,
|
||||
Scheme: r.Scheme,
|
||||
Logger: r.Log.WithValues("Request.Namespace", routing.Namespace, "Request.Name", routing.Name),
|
||||
Ctx: context.TODO(),
|
||||
}
|
||||
|
||||
return ingressesInSync, clusterIngresses, nil
|
||||
var updatedClusterIngresses []networkingv1.Ingress
|
||||
for _, specIngress := range specIngresses {
|
||||
clusterObj, err := sync.SyncObjectWithCluster(&specIngress, clusterAPI)
|
||||
switch t := err.(type) {
|
||||
case nil:
|
||||
break
|
||||
case *sync.NotInSyncError:
|
||||
ingressesInSync = false
|
||||
continue
|
||||
case *sync.UnrecoverableSyncError:
|
||||
return false, nil, t.Cause
|
||||
default:
|
||||
return false, nil, err
|
||||
}
|
||||
updatedClusterIngresses = append(updatedClusterIngresses, *clusterObj.(*networkingv1.Ingress))
|
||||
}
|
||||
|
||||
return ingressesInSync, updatedClusterIngresses, nil
|
||||
}
|
||||
|
||||
func (r *DevWorkspaceRoutingReconciler) getClusterIngresses(routing *controllerv1alpha1.DevWorkspaceRouting) ([]networkingv1.Ingress, error) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package devworkspacerouting
|
||||
|
||||
import (
|
||||
|
|
@ -19,23 +20,14 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/pkg/constants"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/devfile/devworkspace-operator/pkg/provision/sync"
|
||||
routeV1 "github.com/openshift/api/route/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
)
|
||||
|
||||
var routeDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(routeV1.Route{}, "TypeMeta", "ObjectMeta", "Status"),
|
||||
cmpopts.IgnoreFields(routeV1.RouteSpec{}, "WildcardPolicy", "Host"),
|
||||
cmpopts.IgnoreFields(routeV1.RouteTargetReference{}, "Weight"),
|
||||
}
|
||||
|
||||
func (r *DevWorkspaceRoutingReconciler) syncRoutes(routing *controllerv1alpha1.DevWorkspaceRouting, specRoutes []routeV1.Route) (ok bool, clusterRoutes []routeV1.Route, err error) {
|
||||
routesInSync := true
|
||||
|
||||
|
|
@ -53,33 +45,31 @@ func (r *DevWorkspaceRoutingReconciler) syncRoutes(routing *controllerv1alpha1.D
|
|||
routesInSync = false
|
||||
}
|
||||
|
||||
for _, specRoute := range specRoutes {
|
||||
if contains, idx := listContainsRouteByName(specRoute, clusterRoutes); contains {
|
||||
clusterRoute := clusterRoutes[idx]
|
||||
if !cmp.Equal(specRoute, clusterRoute, routeDiffOpts) {
|
||||
r.Log.Info(fmt.Sprintf("Updating route: %s", clusterRoute.Name))
|
||||
if r.DebugLogging {
|
||||
r.Log.Info(fmt.Sprintf("Diff: %s", cmp.Diff(specRoute, clusterRoute, routeDiffOpts)))
|
||||
}
|
||||
// Update route's spec
|
||||
clusterRoute.Spec = specRoute.Spec
|
||||
err := r.Update(context.TODO(), &clusterRoute)
|
||||
if err != nil && !errors.IsConflict(err) {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
routesInSync = false
|
||||
}
|
||||
} else {
|
||||
err := r.Create(context.TODO(), &specRoute)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
routesInSync = false
|
||||
}
|
||||
clusterAPI := sync.ClusterAPI{
|
||||
Client: r.Client,
|
||||
Scheme: r.Scheme,
|
||||
Logger: r.Log.WithValues("Request.Namespace", routing.Namespace, "Request.Name", routing.Name),
|
||||
Ctx: context.TODO(),
|
||||
}
|
||||
|
||||
return routesInSync, clusterRoutes, nil
|
||||
var updatedClusterRoutes []routeV1.Route
|
||||
for _, specIngress := range specRoutes {
|
||||
clusterObj, err := sync.SyncObjectWithCluster(&specIngress, clusterAPI)
|
||||
switch t := err.(type) {
|
||||
case nil:
|
||||
break
|
||||
case *sync.NotInSyncError:
|
||||
routesInSync = false
|
||||
continue
|
||||
case *sync.UnrecoverableSyncError:
|
||||
return false, nil, t.Cause
|
||||
default:
|
||||
return false, nil, err
|
||||
}
|
||||
updatedClusterRoutes = append(updatedClusterRoutes, *clusterObj.(*routeV1.Route))
|
||||
}
|
||||
|
||||
return routesInSync, updatedClusterRoutes, nil
|
||||
}
|
||||
|
||||
func (r *DevWorkspaceRoutingReconciler) getClusterRoutes(routing *controllerv1alpha1.DevWorkspaceRouting) ([]routeV1.Route, error) {
|
||||
|
|
|
|||
|
|
@ -12,50 +12,22 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package devworkspacerouting
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/pkg/constants"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/devfile/devworkspace-operator/pkg/provision/sync"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
controllerv1alpha1 "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
)
|
||||
|
||||
var serviceDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(corev1.Service{}, "TypeMeta", "ObjectMeta", "Status"),
|
||||
cmp.Comparer(func(x, y corev1.ServiceSpec) bool {
|
||||
xCopy := x.DeepCopy()
|
||||
yCopy := y.DeepCopy()
|
||||
if !cmp.Equal(xCopy.Selector, yCopy.Selector) {
|
||||
return false
|
||||
}
|
||||
// Function that takes a slice of servicePorts and returns the appropriate comparison
|
||||
// function to pass to sort.Slice() for that slice of servicePorts.
|
||||
servicePortSorter := func(servicePorts []corev1.ServicePort) func(i, j int) bool {
|
||||
return func(i, j int) bool {
|
||||
return strings.Compare(servicePorts[i].Name, servicePorts[j].Name) > 0
|
||||
}
|
||||
}
|
||||
sort.Slice(xCopy.Ports, servicePortSorter(xCopy.Ports))
|
||||
sort.Slice(yCopy.Ports, servicePortSorter(yCopy.Ports))
|
||||
if !cmp.Equal(xCopy.Ports, yCopy.Ports) {
|
||||
return false
|
||||
}
|
||||
return xCopy.Type == yCopy.Type
|
||||
}),
|
||||
}
|
||||
|
||||
func (r *DevWorkspaceRoutingReconciler) syncServices(routing *controllerv1alpha1.DevWorkspaceRouting, specServices []corev1.Service) (ok bool, clusterServices []corev1.Service, err error) {
|
||||
servicesInSync := true
|
||||
|
||||
|
|
@ -73,34 +45,31 @@ func (r *DevWorkspaceRoutingReconciler) syncServices(routing *controllerv1alpha1
|
|||
servicesInSync = false
|
||||
}
|
||||
|
||||
for _, specService := range specServices {
|
||||
if contains, idx := listContainsByName(specService, clusterServices); contains {
|
||||
clusterService := clusterServices[idx]
|
||||
if !cmp.Equal(specService, clusterService, serviceDiffOpts) {
|
||||
r.Log.Info(fmt.Sprintf("Updating service: %s", clusterService.Name))
|
||||
if r.DebugLogging {
|
||||
r.Log.Info(fmt.Sprintf("Diff: %s", cmp.Diff(specService, clusterService, serviceDiffOpts)))
|
||||
}
|
||||
// Cannot naively copy spec, as clusterIP is unmodifiable
|
||||
clusterIP := clusterService.Spec.ClusterIP
|
||||
clusterService.Spec = specService.Spec
|
||||
clusterService.Spec.ClusterIP = clusterIP
|
||||
err := r.Update(context.TODO(), &clusterService)
|
||||
if err != nil && !errors.IsConflict(err) {
|
||||
return false, nil, err
|
||||
}
|
||||
servicesInSync = false
|
||||
}
|
||||
} else {
|
||||
err := r.Create(context.TODO(), &specService)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
servicesInSync = false
|
||||
}
|
||||
clusterAPI := sync.ClusterAPI{
|
||||
Client: r.Client,
|
||||
Scheme: r.Scheme,
|
||||
Logger: r.Log.WithValues("Request.Namespace", routing.Namespace, "Request.Name", routing.Name),
|
||||
Ctx: context.TODO(),
|
||||
}
|
||||
|
||||
return servicesInSync, clusterServices, nil
|
||||
var updatedClusterServices []corev1.Service
|
||||
for _, specIngress := range specServices {
|
||||
clusterObj, err := sync.SyncObjectWithCluster(&specIngress, clusterAPI)
|
||||
switch t := err.(type) {
|
||||
case nil:
|
||||
break
|
||||
case *sync.NotInSyncError:
|
||||
servicesInSync = false
|
||||
continue
|
||||
case *sync.UnrecoverableSyncError:
|
||||
return false, nil, t.Cause
|
||||
default:
|
||||
return false, nil, err
|
||||
}
|
||||
updatedClusterServices = append(updatedClusterServices, *clusterObj.(*corev1.Service))
|
||||
}
|
||||
|
||||
return servicesInSync, updatedClusterServices, nil
|
||||
}
|
||||
|
||||
func (r *DevWorkspaceRoutingReconciler) getClusterServices(routing *controllerv1alpha1.DevWorkspaceRouting) ([]corev1.Service, error) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package maputils
|
||||
|
||||
func Append(target map[string]string, key, value string) map[string]string {
|
||||
|
|
|
|||
|
|
@ -12,12 +12,15 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/pkg/constants"
|
||||
)
|
||||
|
||||
var NonAlphaNumRegexp = regexp.MustCompile(`[^a-z0-9]+`)
|
||||
|
|
@ -94,3 +97,11 @@ func AutoMountSecretVolumeName(volumeName string) string {
|
|||
func AutoMountPVCVolumeName(pvcName string) string {
|
||||
return fmt.Sprintf("automount-pvc-%s", pvcName)
|
||||
}
|
||||
|
||||
func WorkspaceRoleName() string {
|
||||
return "workspace"
|
||||
}
|
||||
|
||||
func WorkspaceRolebindingName() string {
|
||||
return constants.ServiceAccount + "dw"
|
||||
}
|
||||
|
|
|
|||
145
vendor/github.com/devfile/devworkspace-operator/pkg/config/configmap/config.go
generated
vendored
Normal file
145
vendor/github.com/devfile/devworkspace-operator/pkg/config/configmap/config.go
generated
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
// Copyright (c) 2019-2021 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 configmap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/pkg/infrastructure"
|
||||
)
|
||||
|
||||
var ControllerCfg ControllerConfig
|
||||
var log = logf.Log.WithName("controller_devworkspace_config")
|
||||
|
||||
const (
|
||||
ConfigMapNameEnvVar = "CONTROLLER_CONFIG_MAP_NAME"
|
||||
ConfigMapNamespaceEnvVar = "CONTROLLER_CONFIG_MAP_NAMESPACE"
|
||||
)
|
||||
|
||||
var ConfigMapReference = client.ObjectKey{
|
||||
Namespace: "",
|
||||
Name: "devworkspace-controller-configmap",
|
||||
}
|
||||
|
||||
type ControllerConfig struct {
|
||||
configMap *corev1.ConfigMap
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) update(configMap *corev1.ConfigMap) {
|
||||
log.Info("Updating the configuration from config map '%s' in namespace '%s'", configMap.Name, configMap.Namespace)
|
||||
wc.configMap = configMap
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetWorkspacePVCName() *string {
|
||||
return wc.GetProperty(workspacePVCName)
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetDefaultRoutingClass() *string {
|
||||
return wc.GetProperty(routingClass)
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetClusterRoutingSuffix() *string {
|
||||
return wc.GetProperty(routingSuffix)
|
||||
}
|
||||
|
||||
//GetExperimentalFeaturesEnabled returns true if experimental features should be enabled.
|
||||
//DO NOT TURN ON IT IN THE PRODUCTION.
|
||||
//Experimental features are not well tested and may be totally removed without announcement.
|
||||
func (wc *ControllerConfig) GetExperimentalFeaturesEnabled() *string {
|
||||
return wc.GetProperty(experimentalFeaturesEnabled)
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetPVCStorageClassName() *string {
|
||||
return wc.GetProperty(workspacePVCStorageClassName)
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetSidecarPullPolicy() *string {
|
||||
return wc.GetProperty(sidecarPullPolicy)
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetProperty(name string) *string {
|
||||
val, exists := wc.configMap.Data[name]
|
||||
if exists {
|
||||
return &val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wc *ControllerConfig) GetWorkspaceIdleTimeout() *string {
|
||||
return wc.GetProperty(devworkspaceIdleTimeout)
|
||||
}
|
||||
|
||||
func syncConfigmapFromCluster(client client.Client, obj client.Object) {
|
||||
if obj.GetNamespace() != ConfigMapReference.Namespace ||
|
||||
obj.GetName() != ConfigMapReference.Name {
|
||||
return
|
||||
}
|
||||
if cm, isConfigMap := obj.(*corev1.ConfigMap); isConfigMap {
|
||||
ControllerCfg.update(cm)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func LoadControllerConfig(nonCachedClient client.Client) (found bool, err error) {
|
||||
configMapName, found := os.LookupEnv(ConfigMapNameEnvVar)
|
||||
if found && len(configMapName) > 0 {
|
||||
ConfigMapReference.Name = configMapName
|
||||
}
|
||||
configMapNamespace, found := os.LookupEnv(ConfigMapNamespaceEnvVar)
|
||||
if found && len(configMapNamespace) > 0 {
|
||||
ConfigMapReference.Namespace = configMapNamespace
|
||||
} else {
|
||||
namespace, err := infrastructure.GetNamespace()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ConfigMapReference.Namespace = namespace
|
||||
}
|
||||
|
||||
if ConfigMapReference.Namespace == "" {
|
||||
return false, fmt.Errorf("you should set the namespace of the controller config map through the '%s' environment variable", ConfigMapNamespaceEnvVar)
|
||||
}
|
||||
|
||||
configMap := &corev1.ConfigMap{}
|
||||
log.Info(fmt.Sprintf("Searching for config map '%s' in namespace '%s'", ConfigMapReference.Name, ConfigMapReference.Namespace))
|
||||
err = nonCachedClient.Get(context.TODO(), ConfigMapReference, configMap)
|
||||
if err != nil {
|
||||
if !k8sErrors.IsNotFound(err) {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
} else {
|
||||
log.Info(fmt.Sprintf(" => found config map '%s' in namespace '%s'", configMap.GetObjectMeta().GetName(), configMap.GetObjectMeta().GetNamespace()))
|
||||
}
|
||||
|
||||
if configMap.Data == nil {
|
||||
configMap.Data = map[string]string{}
|
||||
}
|
||||
syncConfigmapFromCluster(nonCachedClient, configMap)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
26
vendor/github.com/devfile/devworkspace-operator/pkg/config/configmap/doc.go
generated
vendored
Normal file
26
vendor/github.com/devfile/devworkspace-operator/pkg/config/configmap/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// Copyright (c) 2019-2021 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 config is used by components to get configuration.
|
||||
//
|
||||
// Typically each configuration property has the default value.
|
||||
// Default value is supposed to be overridden via config map.
|
||||
//
|
||||
// There is the following configuration names convention:
|
||||
// - words are lower-cased
|
||||
// - . is used to separate subcomponents
|
||||
// - _ is used to separate words in the component name
|
||||
//
|
||||
|
||||
package configmap
|
||||
43
vendor/github.com/devfile/devworkspace-operator/pkg/config/configmap/property.go
generated
vendored
Normal file
43
vendor/github.com/devfile/devworkspace-operator/pkg/config/configmap/property.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Copyright (c) 2019-2021 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 configmap
|
||||
|
||||
const (
|
||||
// image pull policy that is applied to every container within workspace
|
||||
sidecarPullPolicy = "devworkspace.sidecar.image_pull_policy"
|
||||
defaultSidecarPullPolicy = "Always"
|
||||
|
||||
// workspacePVCName config property handles the PVC name that should be created and used for all workspaces within one kubernetes namespace
|
||||
workspacePVCName = "devworkspace.pvc.name"
|
||||
defaultWorkspacePVCName = "claim-devworkspace"
|
||||
|
||||
workspacePVCStorageClassName = "devworkspace.pvc.storage_class.name"
|
||||
|
||||
// routingClass defines the default routing class that should be used if user does not specify it explicitly
|
||||
routingClass = "devworkspace.default_routing_class"
|
||||
defaultRoutingClass = "basic"
|
||||
|
||||
// routingSuffix is the base domain for routes/ingresses created on the cluster. All
|
||||
// routes/ingresses will be created with URL http(s)://<unique-to-workspace-part>.<routingSuffix>
|
||||
// is supposed to be used by embedded routing solvers only
|
||||
routingSuffix = "devworkspace.routing.cluster_host_suffix"
|
||||
|
||||
experimentalFeaturesEnabled = "devworkspace.experimental_features_enabled"
|
||||
defaultExperimentalFeaturesEnabled = "false"
|
||||
|
||||
devworkspaceIdleTimeout = "devworkspace.idle_timeout"
|
||||
defaultDevWorkspaceIdleTimeout = "15m"
|
||||
)
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
|
|
|
|||
151
vendor/github.com/devfile/devworkspace-operator/pkg/config/migrate.go
generated
vendored
Normal file
151
vendor/github.com/devfile/devworkspace-operator/pkg/config/migrate.go
generated
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
//
|
||||
// Copyright (c) 2019-2021 Red Hat, Inc.
|
||||
// This program and the accompanying materials are made
|
||||
// available under the terms of the Eclipse Public License 2.0
|
||||
// which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0
|
||||
//
|
||||
// Contributors:
|
||||
// Red Hat, Inc. - initial API and implementation
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
dw "github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
"github.com/devfile/devworkspace-operator/pkg/config/configmap"
|
||||
"github.com/devfile/devworkspace-operator/pkg/infrastructure"
|
||||
)
|
||||
|
||||
func MigrateConfigFromConfigMap(client crclient.Client) error {
|
||||
migratedConfig, err := convertConfigMapToConfigCRD(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if migratedConfig == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespace, err := infrastructure.GetNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterConfig, err := getClusterConfig(namespace, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clusterConfig != nil {
|
||||
// Check using DeepDerivative in case cluster config contains default/additional values -- we only care
|
||||
// that values in migratedConfig are propagated to the cluster DWOC.
|
||||
if equality.Semantic.DeepDerivative(migratedConfig.Config, clusterConfig.Config) {
|
||||
log.Info("Found deprecated operator configmap matching config custom resource. Deleting.")
|
||||
// In case we migrated before but failed to delete
|
||||
return deleteMigratedConfigmap(client)
|
||||
}
|
||||
return fmt.Errorf("found both DevWorkspaceOperatorConfig and configmap on cluster -- cannot migrate")
|
||||
}
|
||||
|
||||
// Set namespace in case obsolete env vars were used to specify a custom namespace for the configmap
|
||||
migratedConfig.Namespace = namespace
|
||||
if err := client.Create(context.Background(), migratedConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Migrated operator configuration from configmap")
|
||||
return deleteMigratedConfigmap(client)
|
||||
}
|
||||
|
||||
func deleteMigratedConfigmap(client crclient.Client) error {
|
||||
obsoleteConfigmap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configmap.ConfigMapReference.Name,
|
||||
Namespace: configmap.ConfigMapReference.Namespace,
|
||||
},
|
||||
}
|
||||
return client.Delete(context.Background(), obsoleteConfigmap)
|
||||
}
|
||||
|
||||
// convertConfigMapToConfigCRD converts a earlier devworkspace configuration configmap (if present)
|
||||
// into a DevWorkspaceOperatorConfig. Values matching the current default config settings are ignored.
|
||||
// If the configmap is not present, or if the configmap is present but all values are default, returns
|
||||
// nil. Returns an error if we fail to load the controller config from configmap.
|
||||
func convertConfigMapToConfigCRD(client crclient.Client) (*dw.DevWorkspaceOperatorConfig, error) {
|
||||
found, err := configmap.LoadControllerConfig(client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
migratedRoutingConfig := &dw.RoutingConfig{}
|
||||
setRoutingConfig := false
|
||||
routingSuffix := configmap.ControllerCfg.GetClusterRoutingSuffix()
|
||||
if routingSuffix != nil && *routingSuffix != DefaultConfig.Routing.ClusterHostSuffix {
|
||||
migratedRoutingConfig.ClusterHostSuffix = *routingSuffix
|
||||
setRoutingConfig = true
|
||||
}
|
||||
defaultRoutingClass := configmap.ControllerCfg.GetDefaultRoutingClass()
|
||||
if defaultRoutingClass != nil && *defaultRoutingClass != DefaultConfig.Routing.DefaultRoutingClass {
|
||||
migratedRoutingConfig.DefaultRoutingClass = *defaultRoutingClass
|
||||
setRoutingConfig = true
|
||||
}
|
||||
|
||||
migratedWorkspaceConfig := &dw.WorkspaceConfig{}
|
||||
setWorkspaceConfig := false
|
||||
storageClassName := configmap.ControllerCfg.GetPVCStorageClassName()
|
||||
if storageClassName != DefaultConfig.Workspace.StorageClassName {
|
||||
migratedWorkspaceConfig.StorageClassName = storageClassName
|
||||
setWorkspaceConfig = true
|
||||
}
|
||||
sidecarPullPolicy := configmap.ControllerCfg.GetSidecarPullPolicy()
|
||||
if sidecarPullPolicy != nil && *sidecarPullPolicy != DefaultConfig.Workspace.ImagePullPolicy {
|
||||
migratedWorkspaceConfig.ImagePullPolicy = *sidecarPullPolicy
|
||||
setWorkspaceConfig = true
|
||||
}
|
||||
idleTimeout := configmap.ControllerCfg.GetWorkspaceIdleTimeout()
|
||||
if idleTimeout != nil && *idleTimeout != DefaultConfig.Workspace.IdleTimeout {
|
||||
migratedWorkspaceConfig.IdleTimeout = *idleTimeout
|
||||
setWorkspaceConfig = true
|
||||
}
|
||||
pvcName := configmap.ControllerCfg.GetWorkspacePVCName()
|
||||
if pvcName != nil && *pvcName != DefaultConfig.Workspace.PVCName {
|
||||
migratedWorkspaceConfig.PVCName = *pvcName
|
||||
setWorkspaceConfig = true
|
||||
}
|
||||
|
||||
var experimentalFeatures *bool
|
||||
experimentalFeaturesStr := configmap.ControllerCfg.GetExperimentalFeaturesEnabled()
|
||||
if experimentalFeaturesStr != nil && *experimentalFeaturesStr == "true" {
|
||||
trueBool := true
|
||||
experimentalFeatures = &trueBool
|
||||
}
|
||||
|
||||
if !setRoutingConfig && !setWorkspaceConfig && experimentalFeatures == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
migratedConfig := &dw.DevWorkspaceOperatorConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: OperatorConfigName,
|
||||
Namespace: configmap.ConfigMapReference.Namespace,
|
||||
},
|
||||
Config: &dw.OperatorConfiguration{},
|
||||
}
|
||||
migratedConfig.Config.EnableExperimentalFeatures = experimentalFeatures
|
||||
if setRoutingConfig {
|
||||
migratedConfig.Config.Routing = migratedRoutingConfig
|
||||
}
|
||||
if setWorkspaceConfig {
|
||||
migratedConfig.Config.Workspace = migratedWorkspaceConfig
|
||||
}
|
||||
return migratedConfig, nil
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
|
|
@ -73,14 +74,13 @@ func SetupControllerConfig(client crclient.Client) error {
|
|||
} else {
|
||||
syncConfigFrom(config)
|
||||
}
|
||||
defaultRoutingSuffix, err := discoverRouteSuffix(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
DefaultConfig.Routing.ClusterHostSuffix = defaultRoutingSuffix
|
||||
if internalConfig.Routing.ClusterHostSuffix == "" {
|
||||
routeSuffix, err := discoverRouteSuffix(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
internalConfig.Routing.ClusterHostSuffix = routeSuffix
|
||||
// Set routing suffix in default config as well to ensure value is persisted across config changes
|
||||
DefaultConfig.Routing.ClusterHostSuffix = routeSuffix
|
||||
internalConfig.Routing.ClusterHostSuffix = defaultRoutingSuffix
|
||||
updatePublicConfig()
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -12,14 +12,60 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package constants
|
||||
|
||||
// Constants that are used in attributes on DevWorkspace elements (components, endpoints, etc.)
|
||||
const (
|
||||
// DevWorkspaceStorageTypeAttribute defines the strategy used for provisioning storage for the workspace.
|
||||
// If empty, the common PVC strategy is used.
|
||||
// Supported options:
|
||||
// - "common": Create one PVC per namespace, and store data for all workspaces in that namespace in that PVC
|
||||
// - "async" : Create one PVC per namespace, and create a remote server that syncs data from workspaces to the PVC.
|
||||
// All volumeMounts used for devworkspaces are emptyDir
|
||||
// - "ephemeral": Use emptyDir volumes for all volumes in the DevWorkspace. All data is lost when the workspace is
|
||||
// stopped.
|
||||
DevWorkspaceStorageTypeAttribute = "controller.devfile.io/storage-type"
|
||||
|
||||
// WorkspaceEnvAttribute is an attribute that specifies a set of environment variables provided by a component
|
||||
// that should be added to all workspace containers. The structure of the attribute value should be a list of
|
||||
// Devfile 2.0 EnvVar, e.g.
|
||||
//
|
||||
// attributes:
|
||||
// workspaceEnv:
|
||||
// - name: ENV_1
|
||||
// value: VAL_1
|
||||
// - name: ENV_2
|
||||
// value: VAL_2
|
||||
WorkspaceEnvAttribute = "workspaceEnv"
|
||||
|
||||
// WorkspaceSCCAttribute defines additional SCCs that should be added to the DevWorkspace. The user adding
|
||||
// this attribute to a workspace must have the RBAC permissions to "use" the SCC with the given name. For example,
|
||||
// to add the 'anyuid' SCC to the workspace Pod, the DevWorkspace should contain
|
||||
//
|
||||
// spec:
|
||||
// template:
|
||||
// attributes:
|
||||
// controller.devfile.io/scc: "anyuid"
|
||||
//
|
||||
// Creating a workspace with this attribute, or updating an existing workspace to include this attribute will fail
|
||||
// if the user making the request does not have the "use" permission for the "anyuid" SCC.
|
||||
// Only supported on OpenShift.
|
||||
WorkspaceSCCAttribute = "controller.devfile.io/scc"
|
||||
|
||||
// ProjectCloneAttribute configures how the DevWorkspace will treat project cloning. By default, an init container
|
||||
// will be added to the workspace deployment to clone projects to the workspace before it starts. This attribute
|
||||
// must be applied to top-level attributes field in the DevWorkspace.
|
||||
// Supported options:
|
||||
// - "disable" - Disable automatic project cloning. No init container will be added to the workspace and projects
|
||||
// will not be cloned into the workspace on start.
|
||||
ProjectCloneAttribute = "controller.devfile.io/project-clone"
|
||||
|
||||
// PluginSourceAttribute is an attribute added to components, commands, and projects in a flattened
|
||||
// DevWorkspace representation to signify where the respective component came from (i.e. which plugin
|
||||
// or parent imported it)
|
||||
PluginSourceAttribute = "controller.devfile.io/imported-by"
|
||||
|
||||
// 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"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// package constants defines constant values used throughout the DevWorkspace Operator
|
||||
|
||||
// Package constants defines constant values used throughout the DevWorkspace Operator
|
||||
package constants
|
||||
|
||||
// Labels which should be used for controller related objects
|
||||
|
|
@ -62,6 +63,7 @@ const (
|
|||
ProjectCloneCPURequest = "100m"
|
||||
|
||||
// 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 = "common"
|
||||
|
|
@ -71,4 +73,9 @@ const (
|
|||
// EphemeralStorageClassType defines the 'ephemeral' storage policy: all volumes are allocated as emptyDir volumes and
|
||||
// so do not require cleanup. When a DevWorkspace is stopped, all local changes are lost.
|
||||
EphemeralStorageClassType = "ephemeral"
|
||||
|
||||
// Constants describing configuration for automatic project cloning
|
||||
|
||||
// ProjectCloneDisable specifies that project cloning should be disabled.
|
||||
ProjectCloneDisable = "disable"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package constants
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -12,9 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package constants
|
||||
|
||||
// Constants that are used in labels and annotation on DevWorkspace-related resources.
|
||||
// Constants that are used in labels and annotations on DevWorkspace-related resources.
|
||||
const (
|
||||
// DevWorkspaceIDLabel is the label key to store workspace identifier
|
||||
DevWorkspaceIDLabel = "controller.devfile.io/devworkspace_id"
|
||||
|
|
@ -25,6 +26,14 @@ const (
|
|||
// DevWorkspaceNameLabel is the label key to store workspace name
|
||||
DevWorkspaceNameLabel = "controller.devfile.io/devworkspace_name"
|
||||
|
||||
// DevWorkspaceWatchConfigMapLabel marks a configmap so that it is watched by the controller. This label is required on all
|
||||
// configmaps that should be seen by the controller
|
||||
DevWorkspaceWatchConfigMapLabel = "controller.devfile.io/watch-configmap"
|
||||
|
||||
// DevWorkspaceWatchSecretLabel marks a secret so that it is watched by the controller. This label is required on all
|
||||
// secrets that should be seen by the controller
|
||||
DevWorkspaceWatchSecretLabel = "controller.devfile.io/watch-secret"
|
||||
|
||||
// DevWorkspaceMountLabel is the label key to store if a configmap or secret should be mounted to the devworkspace
|
||||
DevWorkspaceMountLabel = "controller.devfile.io/mount-to-devworkspace"
|
||||
|
||||
|
|
@ -36,6 +45,14 @@ const (
|
|||
// see https://git-scm.com/docs/git-credential-store#_storage_format for more details
|
||||
DevWorkspaceGitCredentialLabel = "controller.devfile.io/git-credential"
|
||||
|
||||
// DevWorkspaceGitTLSLabel is the label key to specify if the configmap is credentials for accessing a git server.
|
||||
// Configmap must contain the following data:
|
||||
// certificate: the certificate used to access the git server in Base64 ASCII
|
||||
// You can also optionally define the git host.
|
||||
// host: the url of the git server
|
||||
// If the git host is not defined then the certificate will be used for all http repositories.
|
||||
DevWorkspaceGitTLSLabel = "controller.devfile.io/git-tls-credential"
|
||||
|
||||
// DevWorkspaceMountPathAnnotation is the annotation key to store the mount path for the secret or configmap.
|
||||
// If no mount path is provided, configmaps will be mounted at /etc/config/<configmap-name>, secrets will
|
||||
// be mounted at /etc/secret/<secret-name>, and persistent volume claims will be mounted to /tmp/<claim-name>
|
||||
|
|
@ -74,26 +91,21 @@ const (
|
|||
// WebhookRestartedAtAnnotation holds the the time (unixnano) of when the webhook server was forced to restart by controller
|
||||
WebhookRestartedAtAnnotation = "controller.devfile.io/restarted-at"
|
||||
|
||||
// DevWorkspaceStartedAtAnnotation holds the the time (unixnano) of when the devworkspace was started
|
||||
DevWorkspaceStartedAtAnnotation = "controller.devfile.io/started-at"
|
||||
|
||||
// RoutingAnnotationInfix is the infix of the annotations of DevWorkspace that are passed down as annotation to the DevWorkspaceRouting objects.
|
||||
// The full annotation name is supposed to be "<routingClass>.routing.controller.devfile.io/<anything>"
|
||||
RoutingAnnotationInfix = ".routing.controller.devfile.io/"
|
||||
|
||||
// DevWorkspaceStorageTypeAtrr defines the strategy used for provisioning storage for the workspace.
|
||||
// If empty, the common PVC strategy is used.
|
||||
// Supported options:
|
||||
// - "common": Create one PVC per namespace, and store data for all workspaces in that namespace in that PVC
|
||||
// - "async" : Create one PVC per namespace, and create a remote server that syncs data from workspaces to the PVC.
|
||||
// All volumeMounts used for devworkspaces are emptyDir
|
||||
DevWorkspaceStorageTypeAtrr = "controller.devfile.io/storage-type"
|
||||
|
||||
// WorkspaceEndpointNameAnnotation is the annotation key for storing an endpoint's name from the devfile representation
|
||||
// DevWorkspaceEndpointNameAnnotation is the annotation key for storing an endpoint's name from the devfile representation
|
||||
DevWorkspaceEndpointNameAnnotation = "controller.devfile.io/endpoint_name"
|
||||
|
||||
// DevWorkspaceDiscoverableServiceAnnotation marks a service in a devworkspace as created for a discoverable endpoint,
|
||||
// as opposed to a service created to support the devworkspace itself.
|
||||
DevWorkspaceDiscoverableServiceAnnotation = "controller.devfile.io/discoverable-service"
|
||||
|
||||
// PullSecretLabel marks the intention that secret should be used as pull secret for devworkspaces withing namespace
|
||||
// DevWorkspacePullSecretLabel marks the intention that this secret should be used as a pull secret for devworkspaces within namespace
|
||||
// Only secrets with 'true' value will be mount as pull secret
|
||||
// Should be assigned to secrets with type docker config types (kubernetes.io/dockercfg and kubernetes.io/dockerconfigjson)
|
||||
DevWorkspacePullSecretLabel = "controller.devfile.io/devworkspace_pullsecret"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
|
|
|
|||
1
vendor/github.com/devfile/devworkspace-operator/pkg/infrastructure/namespace.go
generated
vendored
1
vendor/github.com/devfile/devworkspace-operator/pkg/infrastructure/namespace.go
generated
vendored
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infrastructure
|
||||
|
||||
import (
|
||||
|
|
|
|||
69
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/cluster_api.go
generated
vendored
Normal file
69
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/cluster_api.go
generated
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2019-2021 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 sync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type ClusterAPI struct {
|
||||
Client crclient.Client
|
||||
NonCachingClient crclient.Client
|
||||
Scheme *runtime.Scheme
|
||||
Logger logr.Logger
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
// NotInSyncError is returned when a spec object is out-of-sync with its cluster counterpart
|
||||
type NotInSyncError struct {
|
||||
Reason NotInSyncReason
|
||||
Object crclient.Object
|
||||
}
|
||||
|
||||
type NotInSyncReason string
|
||||
|
||||
const (
|
||||
UpdatedObjectReason NotInSyncReason = "Updated object"
|
||||
CreatedObjectReason NotInSyncReason = "Created object"
|
||||
DeletedObjectReason NotInSyncReason = "Deleted object"
|
||||
NeedRetryReason NotInSyncReason = "Need to retry"
|
||||
)
|
||||
|
||||
func (e *NotInSyncError) Error() string {
|
||||
return fmt.Sprintf("%s %s is not ready: %s", reflect.TypeOf(e.Object).Elem().String(), e.Object.GetName(), e.Reason)
|
||||
}
|
||||
|
||||
// NewNotInSync wraps creation of NotInSyncErrors for simplicity
|
||||
func NewNotInSync(obj crclient.Object, reason NotInSyncReason) *NotInSyncError {
|
||||
return &NotInSyncError{
|
||||
Reason: reason,
|
||||
Object: obj,
|
||||
}
|
||||
}
|
||||
|
||||
// UnrecoverableSyncError is returned when provided objects cannot be synced with the cluster due to
|
||||
// an unexpected error (e.g. they are invalid according to the object's spec).
|
||||
type UnrecoverableSyncError struct {
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *UnrecoverableSyncError) Error() string {
|
||||
return e.Cause.Error()
|
||||
}
|
||||
135
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diff.go
generated
vendored
Normal file
135
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diff.go
generated
vendored
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) 2019-2021 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 sync
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// diffFunc represents a function that compares a spec object against the corresponding cluster object and
|
||||
// returns whether the object should be deleted or updated.
|
||||
type diffFunc func(spec crclient.Object, cluster crclient.Object) (delete, update bool)
|
||||
|
||||
var diffFuncs = map[reflect.Type]diffFunc{
|
||||
reflect.TypeOf(rbacv1.Role{}): basicDiffFunc(roleDiffOpts),
|
||||
reflect.TypeOf(rbacv1.RoleBinding{}): basicDiffFunc(rolebindingDiffOpts),
|
||||
reflect.TypeOf(corev1.ServiceAccount{}): labelsAndAnnotationsDiffFunc,
|
||||
reflect.TypeOf(appsv1.Deployment{}): allDiffFuncs(deploymentDiffFunc, basicDiffFunc(deploymentDiffOpts)),
|
||||
reflect.TypeOf(corev1.ConfigMap{}): basicDiffFunc(configmapDiffOpts),
|
||||
reflect.TypeOf(v1alpha1.DevWorkspaceRouting{}): allDiffFuncs(routingDiffFunc, labelsAndAnnotationsDiffFunc, basicDiffFunc(routingDiffOpts)),
|
||||
reflect.TypeOf(batchv1.Job{}): jobDiffFunc,
|
||||
reflect.TypeOf(corev1.Service{}): serviceDiffFunc,
|
||||
reflect.TypeOf(networkingv1.Ingress{}): basicDiffFunc(ingressDiffOpts),
|
||||
reflect.TypeOf(routev1.Route{}): basicDiffFunc(routeDiffOpts),
|
||||
}
|
||||
|
||||
// basicDiffFunc returns a diffFunc that specifies an object needs an update if cmp.Equal fails
|
||||
func basicDiffFunc(diffOpt cmp.Options) diffFunc {
|
||||
return func(spec, cluster crclient.Object) (delete, update bool) {
|
||||
return false, !cmp.Equal(spec, cluster, diffOpt)
|
||||
}
|
||||
}
|
||||
|
||||
// labelsAndAnnotationsDiffFunc requires an object to be updated if any label or annotation present in the spec
|
||||
// object is not present in the cluster object.
|
||||
func labelsAndAnnotationsDiffFunc(spec, cluster crclient.Object) (delete, update bool) {
|
||||
clusterAnnotations := cluster.GetAnnotations()
|
||||
for k, v := range spec.GetAnnotations() {
|
||||
if clusterAnnotations[k] != v {
|
||||
return false, true
|
||||
}
|
||||
}
|
||||
clusterLabels := cluster.GetLabels()
|
||||
for k, v := range spec.GetLabels() {
|
||||
if clusterLabels[k] != v {
|
||||
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 {
|
||||
return func(spec, cluster crclient.Object) (delete, update bool) {
|
||||
for _, df := range funcs {
|
||||
shouldDelete, shouldUpdate := df(spec, cluster)
|
||||
if shouldDelete || shouldUpdate {
|
||||
return shouldDelete, shouldUpdate
|
||||
}
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
}
|
||||
|
||||
func deploymentDiffFunc(spec, cluster crclient.Object) (delete, update bool) {
|
||||
specDeploy := spec.(*appsv1.Deployment)
|
||||
clusterDeploy := cluster.(*appsv1.Deployment)
|
||||
if !cmp.Equal(specDeploy.Spec.Selector, clusterDeploy.Spec.Selector) {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func routingDiffFunc(spec, cluster crclient.Object) (delete, update bool) {
|
||||
specRouting := spec.(*v1alpha1.DevWorkspaceRouting)
|
||||
clusterRouting := cluster.(*v1alpha1.DevWorkspaceRouting)
|
||||
if specRouting.Spec.RoutingClass != clusterRouting.Spec.RoutingClass {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func jobDiffFunc(spec, cluster crclient.Object) (delete, update bool) {
|
||||
specJob := spec.(*batchv1.Job)
|
||||
clusterJob := cluster.(*batchv1.Job)
|
||||
// TODO: previously, this delete was specified with a background deletion policy, which is currently unsupported.
|
||||
return !equality.Semantic.DeepDerivative(specJob.Spec, clusterJob.Spec), false
|
||||
}
|
||||
|
||||
func serviceDiffFunc(spec, cluster crclient.Object) (delete, update bool) {
|
||||
specService := spec.(*corev1.Service)
|
||||
clusterService := cluster.(*corev1.Service)
|
||||
specCopy := specService.DeepCopy()
|
||||
clusterCopy := clusterService.DeepCopy()
|
||||
if !cmp.Equal(specCopy.Spec.Selector, clusterCopy.Spec.Selector) {
|
||||
return false, true
|
||||
}
|
||||
// Function that takes a slice of servicePorts and returns the appropriate comparison
|
||||
// function to pass to sort.Slice() for that slice of servicePorts.
|
||||
servicePortSorter := func(servicePorts []corev1.ServicePort) func(i, j int) bool {
|
||||
return func(i, j int) bool {
|
||||
return strings.Compare(servicePorts[i].Name, servicePorts[j].Name) > 0
|
||||
}
|
||||
}
|
||||
sort.Slice(specCopy.Spec.Ports, servicePortSorter(specCopy.Spec.Ports))
|
||||
sort.Slice(clusterCopy.Spec.Ports, servicePortSorter(clusterCopy.Spec.Ports))
|
||||
if !cmp.Equal(specCopy.Spec.Ports, clusterCopy.Spec.Ports) {
|
||||
return false, true
|
||||
}
|
||||
return false, specCopy.Spec.Type != clusterCopy.Spec.Type
|
||||
}
|
||||
72
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diffopts.go
generated
vendored
Normal file
72
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/diffopts.go
generated
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2019-2021 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 sync
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
routeV1 "github.com/openshift/api/route/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
var roleDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(rbacv1.Role{}, "TypeMeta", "ObjectMeta"),
|
||||
}
|
||||
|
||||
var rolebindingDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(rbacv1.RoleBinding{}, "TypeMeta", "ObjectMeta"),
|
||||
cmpopts.IgnoreFields(rbacv1.RoleRef{}, "APIGroup"),
|
||||
cmpopts.IgnoreFields(rbacv1.Subject{}, "APIGroup"),
|
||||
}
|
||||
|
||||
var deploymentDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(appsv1.Deployment{}, "TypeMeta", "ObjectMeta", "Status"),
|
||||
cmpopts.IgnoreFields(appsv1.DeploymentSpec{}, "RevisionHistoryLimit", "ProgressDeadlineSeconds"),
|
||||
cmpopts.IgnoreFields(corev1.PodSpec{}, "DNSPolicy", "SchedulerName", "DeprecatedServiceAccount"),
|
||||
cmpopts.IgnoreFields(corev1.Container{}, "TerminationMessagePath", "TerminationMessagePolicy", "ImagePullPolicy"),
|
||||
cmpopts.SortSlices(func(a, b corev1.Container) bool {
|
||||
return strings.Compare(a.Name, b.Name) > 0
|
||||
}),
|
||||
cmpopts.SortSlices(func(a, b corev1.Volume) bool {
|
||||
return strings.Compare(a.Name, b.Name) > 0
|
||||
}),
|
||||
cmpopts.SortSlices(func(a, b corev1.VolumeMount) bool {
|
||||
return strings.Compare(a.Name, b.Name) > 0
|
||||
}),
|
||||
}
|
||||
|
||||
var configmapDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(corev1.ConfigMap{}, "TypeMeta", "ObjectMeta"),
|
||||
}
|
||||
|
||||
var routingDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(v1alpha1.DevWorkspaceRouting{}, "ObjectMeta", "TypeMeta", "Status"),
|
||||
}
|
||||
|
||||
var routeDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(routeV1.Route{}, "TypeMeta", "ObjectMeta", "Status"),
|
||||
cmpopts.IgnoreFields(routeV1.RouteSpec{}, "WildcardPolicy", "Host"),
|
||||
cmpopts.IgnoreFields(routeV1.RouteTargetReference{}, "Weight"),
|
||||
}
|
||||
|
||||
var ingressDiffOpts = cmp.Options{
|
||||
cmpopts.IgnoreFields(networkingv1.Ingress{}, "TypeMeta", "ObjectMeta", "Status"),
|
||||
cmpopts.IgnoreFields(networkingv1.HTTPIngressPath{}, "PathType"),
|
||||
}
|
||||
150
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go
generated
vendored
Normal file
150
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/sync.go
generated
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (c) 2019-2021 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 sync
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
|
||||
"github.com/devfile/devworkspace-operator/pkg/config"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// SyncObjectWithCluster synchronises the state of specObj to the cluster, creating or updating the cluster object
|
||||
// as required. If specObj is in sync with the cluster, returns the object as it exists on the cluster. Returns a
|
||||
// NotInSyncError if an update is required, UnrecoverableSyncError if object provided is invalid, or generic error
|
||||
// if an unexpected error is encountered
|
||||
func SyncObjectWithCluster(specObj crclient.Object, api ClusterAPI) (crclient.Object, error) {
|
||||
objType := reflect.TypeOf(specObj).Elem()
|
||||
clusterObj := reflect.New(objType).Interface().(crclient.Object)
|
||||
|
||||
err := api.Client.Get(api.Ctx, types.NamespacedName{Name: specObj.GetName(), Namespace: specObj.GetNamespace()}, clusterObj)
|
||||
if err != nil {
|
||||
if k8sErrors.IsNotFound(err) {
|
||||
return nil, createObjectGeneric(specObj, api)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isMutableObject(specObj) { // TODO: we could still update labels here, or treat a need to update as a fatal error
|
||||
return clusterObj, nil
|
||||
}
|
||||
|
||||
diffFunc := diffFuncs[objType]
|
||||
if diffFunc == nil {
|
||||
return nil, &UnrecoverableSyncError{fmt.Errorf("attempting to sync unrecognized object %s", objType)}
|
||||
}
|
||||
shouldDelete, shouldUpdate := diffFunc(specObj, clusterObj)
|
||||
if shouldDelete {
|
||||
printDiff(specObj, clusterObj, api.Logger)
|
||||
err := api.Client.Delete(api.Ctx, specObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
api.Logger.Info("Deleted object", "kind", objType.String(), "name", specObj.GetName())
|
||||
return nil, NewNotInSync(specObj, DeletedObjectReason)
|
||||
}
|
||||
if shouldUpdate {
|
||||
printDiff(specObj, clusterObj, api.Logger)
|
||||
return nil, updateObjectGeneric(specObj, clusterObj, api)
|
||||
}
|
||||
return clusterObj, nil
|
||||
}
|
||||
|
||||
func createObjectGeneric(specObj crclient.Object, api ClusterAPI) error {
|
||||
err := api.Client.Create(api.Ctx, specObj)
|
||||
switch {
|
||||
case err == nil:
|
||||
api.Logger.Info("Created object", "kind", reflect.TypeOf(specObj).Elem().String(), "name", specObj.GetName())
|
||||
return NewNotInSync(specObj, CreatedObjectReason)
|
||||
case k8sErrors.IsAlreadyExists(err):
|
||||
// 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):
|
||||
return &UnrecoverableSyncError{err}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func updateObjectGeneric(specObj, clusterObj crclient.Object, api ClusterAPI) error {
|
||||
updateFunc := getUpdateFunc(specObj)
|
||||
updatedObj, err := updateFunc(specObj, clusterObj)
|
||||
if err != nil {
|
||||
if err := api.Client.Delete(api.Ctx, specObj); err != nil {
|
||||
return err
|
||||
}
|
||||
api.Logger.Info("Deleted object", "kind", reflect.TypeOf(specObj).Elem().String(), "name", specObj.GetName())
|
||||
return NewNotInSync(specObj, DeletedObjectReason)
|
||||
}
|
||||
|
||||
err = api.Client.Update(api.Ctx, updatedObj)
|
||||
switch {
|
||||
case err == nil:
|
||||
api.Logger.Info("Updated object", "kind", reflect.TypeOf(specObj).Elem().String(), "name", specObj.GetName())
|
||||
return NewNotInSync(specObj, UpdatedObjectReason)
|
||||
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):
|
||||
return &UnrecoverableSyncError{err}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func isMutableObject(obj crclient.Object) bool {
|
||||
switch obj.(type) {
|
||||
case *corev1.PersistentVolumeClaim:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func printDiff(specObj, clusterObj crclient.Object, log logr.Logger) {
|
||||
if config.ExperimentalFeaturesEnabled() {
|
||||
var diffOpts cmp.Options
|
||||
switch specObj.(type) {
|
||||
case *rbacv1.Role:
|
||||
diffOpts = roleDiffOpts
|
||||
case *rbacv1.RoleBinding:
|
||||
diffOpts = rolebindingDiffOpts
|
||||
case *appsv1.Deployment:
|
||||
diffOpts = deploymentDiffOpts
|
||||
case *corev1.ConfigMap:
|
||||
diffOpts = configmapDiffOpts
|
||||
case *v1alpha1.DevWorkspaceRouting:
|
||||
diffOpts = routingDiffOpts
|
||||
case *networkingv1.Ingress:
|
||||
diffOpts = ingressDiffOpts
|
||||
case *routev1.Route:
|
||||
diffOpts = routeDiffOpts
|
||||
default:
|
||||
diffOpts = nil
|
||||
}
|
||||
log.Info(fmt.Sprintf("Diff: %s", cmp.Diff(specObj, clusterObj, diffOpts)))
|
||||
}
|
||||
}
|
||||
61
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/update.go
generated
vendored
Normal file
61
vendor/github.com/devfile/devworkspace-operator/pkg/provision/sync/update.go
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 2019-2021 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 sync
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// updateFunc returns the object that should be applied to the client.Update function
|
||||
// when updating an object on the cluster. Typically, this will just be defaultUpdateFunc,
|
||||
// which returns the spec obejct unmodified. However, some objects, such as Services, require
|
||||
// fields to be copied over from the cluster object, e.g. .spec.clusterIP. If an updated object
|
||||
// cannot be resolved, an error should be returned to signal that the object in question should
|
||||
// be deleted instead.
|
||||
//
|
||||
// The 'cluster' argument may be specified as nil in the case where a cluster version of the
|
||||
// spec object is inaccessible (not cached) and has to be handled specifically.
|
||||
type updateFunc func(spec, cluster crclient.Object) (crclient.Object, error)
|
||||
|
||||
func defaultUpdateFunc(spec, cluster crclient.Object) (crclient.Object, error) {
|
||||
if cluster != nil {
|
||||
spec.SetResourceVersion(cluster.GetResourceVersion())
|
||||
}
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func serviceUpdateFunc(spec, cluster crclient.Object) (crclient.Object, error) {
|
||||
if cluster == nil {
|
||||
return nil, errors.New("updating a service requires the cluster instance")
|
||||
}
|
||||
specService := spec.DeepCopyObject().(*corev1.Service)
|
||||
clusterService := cluster.(*corev1.Service)
|
||||
specService.ResourceVersion = clusterService.ResourceVersion
|
||||
specService.Spec.ClusterIP = clusterService.Spec.ClusterIP
|
||||
return specService, nil
|
||||
}
|
||||
|
||||
func getUpdateFunc(obj crclient.Object) updateFunc {
|
||||
objType := reflect.TypeOf(obj).Elem()
|
||||
switch objType {
|
||||
case reflect.TypeOf(corev1.Service{}):
|
||||
return serviceUpdateFunc
|
||||
default:
|
||||
return defaultUpdateFunc
|
||||
}
|
||||
}
|
||||
0
vendor/google.golang.org/appengine/internal/regen.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/appengine/internal/regen.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/appengine/travis_install.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/appengine/travis_install.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/appengine/travis_test.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/appengine/travis_test.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh
generated
vendored
Executable file → Normal file
0
vendor/google.golang.org/grpc/internal/binarylog/regenerate.sh
generated
vendored
Executable file → Normal file
|
|
@ -33,12 +33,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-20210713124824-03e023e7078b
|
||||
# github.com/devfile/api/v2 v2.0.0-20210917193329-089a48011460
|
||||
## 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.2.1-0.20211005102315-728dff7e987c
|
||||
# github.com/devfile/devworkspace-operator v0.2.1-0.20211213140302-4226bdb05e56
|
||||
## explicit
|
||||
github.com/devfile/devworkspace-operator/apis/controller/v1alpha1
|
||||
github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting
|
||||
|
|
@ -46,8 +46,10 @@ github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerout
|
|||
github.com/devfile/devworkspace-operator/internal/map
|
||||
github.com/devfile/devworkspace-operator/pkg/common
|
||||
github.com/devfile/devworkspace-operator/pkg/config
|
||||
github.com/devfile/devworkspace-operator/pkg/config/configmap
|
||||
github.com/devfile/devworkspace-operator/pkg/constants
|
||||
github.com/devfile/devworkspace-operator/pkg/infrastructure
|
||||
github.com/devfile/devworkspace-operator/pkg/provision/sync
|
||||
# github.com/dgrijalva/jwt-go v3.2.0+incompatible => github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/dgrijalva/jwt-go
|
||||
# github.com/evanphx/json-patch v4.11.0+incompatible => github.com/evanphx/json-patch v4.11.0+incompatible
|
||||
|
|
@ -886,7 +888,7 @@ sigs.k8s.io/yaml
|
|||
# github.com/huandu/xstrings => github.com/huandu/xstrings v1.2.0
|
||||
# github.com/imdario/mergo => github.com/imdario/mergo v0.3.5
|
||||
# github.com/inconshreveable/mousetrap => github.com/inconshreveable/mousetrap v1.0.0
|
||||
# github.com/irifrance/gini => github.com/irifrance/gini v1.0.1
|
||||
# github.com/irifrance/gini => github.com/go-air/gini v1.0.1
|
||||
# github.com/itchyny/astgen-go => github.com/itchyny/astgen-go v0.0.0-20200519013840-cf3ea398f645
|
||||
# github.com/itchyny/go-flags => github.com/itchyny/go-flags v1.5.0
|
||||
# github.com/itchyny/gojq => github.com/itchyny/gojq v0.11.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue