diff --git a/Gopkg.lock b/Gopkg.lock index 9063453c..c2cb49d7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1101,12 +1101,24 @@ pruneopts = "NUT" revision = "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" +[[projects]] + branch = "master" + digest = "1:3c393927d627423c692f266bca75f0ad75e1aa263c121ff31a937bb498650f8b" + name = "knative.dev/caching" + packages = [ + "pkg/apis/caching", + "pkg/apis/caching/v1alpha1", + ] + pruneopts = "NUT" + revision = "55b45efbc4dbbafd5b9010daa023d1ce9edb0ec7" + [[projects]] branch = "master" digest = "1:c52d9005360d444a40d9102248365aecb89b85f85e26abaeb5dc0988bcda3ecf" name = "knative.dev/pkg" packages = [ "apis", + "kmeta", "kmp", ] pruneopts = "T" @@ -1218,6 +1230,7 @@ "k8s.io/gengo/args", "k8s.io/kube-openapi/cmd/openapi-gen", "k8s.io/kube-openapi/pkg/common", + "knative.dev/caching/pkg/apis/caching/v1alpha1", "knative.dev/pkg/apis", "sigs.k8s.io/controller-runtime/pkg/client", "sigs.k8s.io/controller-runtime/pkg/client/config", diff --git a/Gopkg.toml b/Gopkg.toml index 1b8f929c..ee82299d 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -8,6 +8,7 @@ required = [ "k8s.io/code-generator/cmd/informer-gen", "k8s.io/kube-openapi/cmd/openapi-gen", "k8s.io/gengo/args", + "knative.dev/caching/pkg/apis/caching/v1alpha1", "github.com/knative/test-infra/scripts", "github.com/knative/test-infra/tools/dep-collector", "sigs.k8s.io/controller-tools/pkg/crd/generator", diff --git a/config/crds/serving_v1alpha1_knativeserving_crd.yaml b/config/crds/serving_v1alpha1_knativeserving_crd.yaml index 765ff28d..1b0981e2 100644 --- a/config/crds/serving_v1alpha1_knativeserving_crd.yaml +++ b/config/crds/serving_v1alpha1_knativeserving_crd.yaml @@ -51,6 +51,20 @@ spec: description: A means to override the corresponding entries in the upstream configmaps type: object + registry: + description: A means to override the corresponding deployment images in the upstream. + This affects both apps/v1.Deployment and caching.internal.knative.dev/v1alpha1.Image. + type: object + properties: + default: + description: The default image reference template to use for all knative images. + Takes the form of example-registry.io/custom/path/${NAME}:custom-tag + type: string + override: + description: A map of a container name or image name to the full image location of the individual knative image. + type: object + additionalProperties: + type: string type: object status: description: Status defines the observed state of KnativeServing diff --git a/pkg/apis/serving/v1alpha1/knativeserving_types.go b/pkg/apis/serving/v1alpha1/knativeserving_types.go index 476b0788..5ea1e9c0 100644 --- a/pkg/apis/serving/v1alpha1/knativeserving_types.go +++ b/pkg/apis/serving/v1alpha1/knativeserving_types.go @@ -16,8 +16,8 @@ limitations under the License. package v1alpha1 import ( - "knative.dev/pkg/apis" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! @@ -28,6 +28,23 @@ const ( DeploymentsAvailable apis.ConditionType = "DeploymentsAvailable" ) +// Registry defines image overrides of knative images. +// This affects both apps/v1.Deployment and caching.internal.knative.dev/v1alpha1.Image. +// The default value is used as a default format to override for all knative deployments. +// The override values are specific to each knative deployment. +// +k8s:openapi-gen=true +type Registry struct { + // The default image reference template to use for all knative images. + // It takes the form of example-registry.io/custom/path/${NAME}:custom-tag + // ${NAME} will be replaced by the deployment container name, or caching.internal.knative.dev/v1alpha1/Image name. + // +optional + Default string `json:"default,omitempty"` + + // A map of a container name or image name to the full image location of the individual knative image. + // +optional + Override map[string]string `json:"override,omitempty"` +} + // KnativeServingSpec defines the desired state of KnativeServing // +k8s:openapi-gen=true type KnativeServingSpec struct { @@ -38,6 +55,11 @@ type KnativeServingSpec struct { // A means to override the corresponding entries in the upstream configmaps // +optional Config map[string]map[string]string `json:"config,omitempty"` + + // A means to override the corresponding deployment images in the upstream. + // If no registry is provided, the knative release images will be used. + // +optional + Registry Registry `json:"registry,omitempty"` } // KnativeServingStatus defines the observed state of KnativeServing diff --git a/pkg/controller/knativeserving/common/helpers.go b/pkg/controller/knativeserving/common/config_maps.go similarity index 92% rename from pkg/controller/knativeserving/common/helpers.go rename to pkg/controller/knativeserving/common/config_maps.go index 17871db1..c1df6fbe 100644 --- a/pkg/controller/knativeserving/common/helpers.go +++ b/pkg/controller/knativeserving/common/config_maps.go @@ -20,7 +20,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -// Set some data in a configmap, only overwriting common keys if they differ +// UpdateConfigMap set some data in a configmap, only overwriting common keys if they differ func UpdateConfigMap(cm *unstructured.Unstructured, data map[string]string, log logr.Logger) { for k, v := range data { message := []interface{}{"map", cm.GetName(), k, v} diff --git a/pkg/controller/knativeserving/common/extensions.go b/pkg/controller/knativeserving/common/extensions.go index 2eca9493..d04cfac7 100644 --- a/pkg/controller/knativeserving/common/extensions.go +++ b/pkg/controller/knativeserving/common/extensions.go @@ -18,8 +18,10 @@ package common import ( mf "github.com/jcrossley3/manifestival" servingv1alpha1 "github.com/knative/serving-operator/pkg/apis/serving/v1alpha1" + appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + caching "knative.dev/caching/pkg/apis/caching/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/client" logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) @@ -48,7 +50,8 @@ func (platforms Platforms) Extend(c client.Client, scheme *runtime.Scheme) (resu return } -func (exts Extensions) Transform(instance *servingv1alpha1.KnativeServing) []mf.Transformer { +func (exts Extensions) Transform(scheme *runtime.Scheme, instance *servingv1alpha1.KnativeServing) []mf.Transformer { + log.V(1).Info("Transforming", "instance", instance) result := []mf.Transformer{ mf.InjectOwner(instance), mf.InjectNamespace(instance.GetNamespace()), @@ -56,8 +59,15 @@ func (exts Extensions) Transform(instance *servingv1alpha1.KnativeServing) []mf. for _, extension := range exts { result = append(result, extension.Transformers...) } - // Let any config in instance override everything else return append(result, func(u *unstructured.Unstructured) error { + // Update the deployment with the new registry and tag + if u.GetAPIVersion() == "caching.internal.knative.dev/v1alpha1" && u.GetKind() == "Image" { + updateCachingImage(scheme, instance, u) + } + if u.GetKind() == "Deployment" { + updateDeployment(scheme, instance, u) + } + // Let any config in instance override everything else if u.GetKind() == "ConfigMap" { if data, ok := instance.Spec.Config[u.GetName()[len(`config-`):]]; ok { UpdateConfigMap(u, data, log) @@ -67,6 +77,40 @@ func (exts Extensions) Transform(instance *servingv1alpha1.KnativeServing) []mf. }) } +func updateCachingImage(scheme *runtime.Scheme, instance *servingv1alpha1.KnativeServing, u *unstructured.Unstructured) error { + var image = &caching.Image{} + err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, image) + if err != nil { + log.Error(err, "Error converting Unstructured to Image", "unstructured", u, "image", image) + return err + } + + registry := instance.Spec.Registry + log.V(1).Info("Updating Image", "name", u.GetName(), "registry", registry) + + UpdateImageSpec(image, ®istry, log) + scheme.Convert(image, u, nil) + log.V(1).Info("Finished conversion", "name", u.GetName(), "unstructured", u.Object) + return nil +} + +func updateDeployment(scheme *runtime.Scheme, instance *servingv1alpha1.KnativeServing, u *unstructured.Unstructured) error { + var deployment = &appsv1.Deployment{} + err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, deployment) + if err != nil { + log.Error(err, "Error converting Unstructured to Deployment", "unstructured", u, "deployment", deployment) + return err + } + + registry := instance.Spec.Registry + log.V(1).Info("Updating Deployment", "name", u.GetName(), "registry", registry) + + UpdateDeploymentImage(deployment, ®istry, log) + scheme.Convert(deployment, u, nil) + log.V(1).Info("Finished conversion", "name", u.GetName(), "unstructured", u.Object) + return nil +} + func (exts Extensions) PreInstall(instance *servingv1alpha1.KnativeServing) error { for _, extension := range exts { for _, f := range extension.PreInstalls { diff --git a/pkg/controller/knativeserving/common/images.go b/pkg/controller/knativeserving/common/images.go new file mode 100644 index 00000000..f1e3b79d --- /dev/null +++ b/pkg/controller/knativeserving/common/images.go @@ -0,0 +1,72 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package common + +import ( + "fmt" + "strings" + + "github.com/go-logr/logr" + servingv1alpha1 "github.com/knative/serving-operator/pkg/apis/serving/v1alpha1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + caching "knative.dev/caching/pkg/apis/caching/v1alpha1" +) + +var ( + // The string to be replaced by the container name + containerNameVariable = "${NAME}" +) + +// UpdateDeploymentImage updates the image of the deployment with a new registry and tag +func UpdateDeploymentImage(deployment *appsv1.Deployment, registry *servingv1alpha1.Registry, log logr.Logger) { + containers := deployment.Spec.Template.Spec.Containers + for index := range containers { + container := &containers[index] + newImage := getNewImage(registry, container.Name) + if newImage != "" { + updateContainer(container, newImage, log) + } + } + log.V(1).Info("Finished updating images", "deployment", deployment.GetName()) +} + +// UpdateImageSpec updates the image of a with a new registry and tag +func UpdateImageSpec(image *caching.Image, registry *servingv1alpha1.Registry, log logr.Logger) { + newImage := getNewImage(registry, image.Name) + if newImage != "" { + log.V(1).Info(fmt.Sprintf("Updating image from: %v, to: %v", image.Spec.Image, newImage)) + image.Spec.Image = newImage + } + log.V(1).Info("Finished updating image", "image", image.GetName()) +} + +func getNewImage(registry *servingv1alpha1.Registry, containerName string) string { + overrideImage := registry.Override[containerName] + if overrideImage != "" { + return overrideImage + } + return replaceName(registry.Default, containerName) +} + +func updateContainer(container *corev1.Container, newImage string, log logr.Logger) { + log.V(1).Info(fmt.Sprintf("Updating container image from: %v, to: %v", container.Image, newImage)) + container.Image = newImage +} + +func replaceName(imageTemplate string, name string) string { + return strings.ReplaceAll(imageTemplate, containerNameVariable, name) +} diff --git a/pkg/controller/knativeserving/common/images_test.go b/pkg/controller/knativeserving/common/images_test.go new file mode 100644 index 00000000..fcbb2aaf --- /dev/null +++ b/pkg/controller/knativeserving/common/images_test.go @@ -0,0 +1,172 @@ +package common + +import ( + "testing" + + servingv1alpha1 "github.com/knative/serving-operator/pkg/apis/serving/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + caching "knative.dev/caching/pkg/apis/caching/v1alpha1" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + appsv1 "k8s.io/api/apps/v1" +) + +type updateDeploymentImageTest struct { + name string + containers []corev1.Container + registry servingv1alpha1.Registry + expected []string +} + +var updateDeploymentImageTests = []updateDeploymentImageTest{ + { + name: "UsesNameFromDefault", + containers: []corev1.Container{{ + Name: "queue", + Image: "gcr.io/knative-releases/github.com/knative/serving/cmd/queue@sha256:1e40c99ff5977daa2d69873fff604c6d09651af1f9ff15aadf8849b3ee77ab45"}, + }, + registry: servingv1alpha1.Registry{ + Default: "new-registry.io/test/path/${NAME}:new-tag", + }, + expected: []string{"new-registry.io/test/path/queue:new-tag"}, + }, + { + name: "UsesContainerNamePerContainer", + containers: []corev1.Container{ + { + Name: "container1", + Image: "gcr.io/cmd/queue:test", + }, + { + Name: "container2", + Image: "gcr.io/cmd/queue:test", + }, + }, + registry: servingv1alpha1.Registry{ + Override: map[string]string{ + "container1": "new-registry.io/test/path/new-container-1:new-tag", + "container2": "new-registry.io/test/path/new-container-2:new-tag", + }, + }, + expected: []string{ + "new-registry.io/test/path/new-container-1:new-tag", + "new-registry.io/test/path/new-container-2:new-tag", + }, + }, + { + name: "UsesOverrideFromDefault", + containers: []corev1.Container{{ + Name: "queue", + Image: "gcr.io/knative-releases/github.com/knative/serving/cmd/queue@sha256:1e40c99ff5977daa2d69873fff604c6d09651af1f9ff15aadf8849b3ee77ab45"}, + }, + registry: servingv1alpha1.Registry{ + Default: "new-registry.io/test/path/${NAME}:new-tag", + Override: map[string]string{ + "queue": "new-registry.io/test/path/new-value:new-override-tag", + }, + }, + expected: []string{"new-registry.io/test/path/new-value:new-override-tag"}, + }, + { + name: "NoChangeOverrideWithDifferentName", + containers: []corev1.Container{{ + Name: "image", + Image: "docker.io/name/image:tag2"}, + }, + registry: servingv1alpha1.Registry{ + Override: map[string]string{ + "Unused": "new-registry.io/test/path", + }, + }, + expected: []string{"docker.io/name/image:tag2"}, + }, + { + name: "NoChange", + containers: []corev1.Container{{ + Name: "queue", + Image: "gcr.io/knative-releases/github.com/knative/serving/cmd/queue@sha256:1e40c99ff5977daa2d69873fff604c6d09651af1f9ff15aadf8849b3ee77ab45"}, + }, + registry: servingv1alpha1.Registry{}, + expected: []string{"gcr.io/knative-releases/github.com/knative/serving/cmd/queue@sha256:1e40c99ff5977daa2d69873fff604c6d09651af1f9ff15aadf8849b3ee77ab45"}, + }, +} + +func TestUpdateDeploymentImage(t *testing.T) { + for _, tt := range updateDeploymentImageTests { + t.Run(tt.name, func(t *testing.T) { + runUpdateDeploymentImageTest(t, tt) + }) + } +} +func runUpdateDeploymentImageTest(t *testing.T, tt updateDeploymentImageTest) { + deployment := appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: tt.name, + }, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: tt.containers, + }, + }, + }, + } + log := logf.Log.WithName(tt.name) + logf.SetLogger(logf.ZapLogger(true)) + + UpdateDeploymentImage(&deployment, &tt.registry, log) + + for i, expected := range tt.expected { + assertEqual(t, deployment.Spec.Template.Spec.Containers[i].Image, expected) + } +} + +type updateImageSpecTest struct { + name string + in string + registry servingv1alpha1.Registry + expected string +} + +var updateImageSpecTests = []updateImageSpecTest{ + { + name: "UsesNameFromDefault", + in: "gcr.io/knative-releases/github.com/knative/serving/cmd/queue@sha256:1e40c99ff5977daa2d69873fff604c6d09651af1f9ff15aadf8849b3ee77ab45", + registry: servingv1alpha1.Registry{ + Default: "new-registry.io/test/path/${NAME}:new-tag", + }, + expected: "new-registry.io/test/path/UsesNameFromDefault:new-tag", + }, +} + +func TestUpdateImageSpec(t *testing.T) { + for _, tt := range updateImageSpecTests { + t.Run(tt.name, func(t *testing.T) { + runUpdateImageSpecTest(t, tt) + }) + } +} +func runUpdateImageSpecTest(t *testing.T, tt updateImageSpecTest) { + image := caching.Image{ + ObjectMeta: metav1.ObjectMeta{ + Name: tt.name, + }, + Spec: caching.ImageSpec{ + Image: tt.in, + }, + } + log := logf.Log.WithName(tt.name) + logf.SetLogger(logf.ZapLogger(true)) + + UpdateImageSpec(&image, &tt.registry, log) + + assertEqual(t, image.Spec.Image, tt.expected) +} + +func assertEqual(t *testing.T, actual, expected string) { + if actual == expected { + return + } + t.Fatalf("expected does not equal actual. \nExpected: %v\nActual: %v", expected, actual) +} diff --git a/pkg/controller/knativeserving/knativeserving_controller.go b/pkg/controller/knativeserving/knativeserving_controller.go index 1d9ff4a9..4a412bc4 100644 --- a/pkg/controller/knativeserving/knativeserving_controller.go +++ b/pkg/controller/knativeserving/knativeserving_controller.go @@ -196,7 +196,7 @@ func (r *ReconcileKnativeServing) install(instance *servingv1alpha1.KnativeServi return err } - err = r.config.Transform(extensions.Transform(instance)...) + err = r.config.Transform(extensions.Transform(r.scheme, instance)...) if err == nil { err = extensions.PreInstall(instance) if err == nil { diff --git a/vendor/knative.dev/caching/LICENSE b/vendor/knative.dev/caching/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/vendor/knative.dev/caching/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/knative.dev/caching/pkg/apis/caching/register.go b/vendor/knative.dev/caching/pkg/apis/caching/register.go new file mode 100644 index 00000000..c938440a --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/register.go @@ -0,0 +1,27 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package caching + +const ( + GroupName = "caching.internal.knative.dev" + + // ImageClassAnnotationKey is the annotation for the explicit class of caching + // that a particular resource has opted into. For example, + // caching.knative.dev/image.class: foo + // This uses a different domain because unlike the resource, it is user-facing. + ImageClassAnnotationKey = "caching.knative.dev/image.class" +) diff --git a/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/doc.go b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/doc.go new file mode 100644 index 00000000..a2dc6cb0 --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=caching.internal.knative.dev +package v1alpha1 diff --git a/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_defaults.go b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_defaults.go new file mode 100644 index 00000000..5aa4471c --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_defaults.go @@ -0,0 +1,23 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import "context" + +func (r *Image) SetDefaults(ctx context.Context) { + // TODO(mattmoor): This +} diff --git a/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_types.go b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_types.go new file mode 100644 index 00000000..3bad8776 --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_types.go @@ -0,0 +1,180 @@ +/* +Copyright 2018 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "reflect" + "sort" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Image is a Knative abstraction that encapsulates the interface by which Knative +// components express a desire to have a particular image cached. +type Image struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec holds the desired state of the Image (from the client). + // +optional + Spec ImageSpec `json:"spec,omitempty"` + + // Status communicates the observed state of the Image (from the controller). + // +optional + Status ImageStatus `json:"status,omitempty"` +} + +// Check that Image can be validated and defaulted. +var _ apis.Validatable = (*Image)(nil) +var _ apis.Defaultable = (*Image)(nil) +var _ kmeta.OwnerRefable = (*Image)(nil) + +// ImageSpec holds the desired state of the Image (from the client). +type ImageSpec struct { + + // Image is the name of the container image url to cache across the cluster. + Image string `json:"image"` + + // ServiceAccountName is the name of the Kubernetes ServiceAccount as which the Pods + // will run this container. This is potentially used to authenticate the image pull + // if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // ImagePullSecrets contains the names of the Kubernetes Secrets containing login + // information used by the Pods which will run this container. + // +optional + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` +} + +// ImageConditionType is used to communicate the status of the reconciliation process. +type ImageConditionType string + +const ( + // ImageConditionReady is set when the revision is starting to materialize + // runtime resources, and becomes true when those resources are ready. + ImageConditionReady ImageConditionType = "Ready" +) + +// ImageCondition defines a readiness condition for a Image. +// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties +type ImageCondition struct { + Type ImageConditionType `json:"type" description:"type of Image condition"` + + Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` + + // +optional + // We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic + // differences (all other things held constant). + LastTransitionTime apis.VolatileTime `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"` + + // +optional + Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"` + + // +optional + Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"` +} + +// ImageStatus communicates the observed state of the Image (from the controller). +type ImageStatus struct { + // Conditions communicates information about ongoing/complete + // reconciliation processes that bring the "spec" inline with the observed + // state of the world. + // +optional + Conditions []ImageCondition `json:"conditions,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ImageList is a list of Image resources +type ImageList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Image `json:"items"` +} + +// IsReady looks at the conditions and if the Status has a condition +// ImageConditionReady returns true if ConditionStatus is True +func (rs *ImageStatus) IsReady() bool { + if c := rs.GetCondition(ImageConditionReady); c != nil { + return c.Status == corev1.ConditionTrue + } + return false +} + +func (rs *ImageStatus) GetCondition(t ImageConditionType) *ImageCondition { + for _, cond := range rs.Conditions { + if cond.Type == t { + return &cond + } + } + return nil +} + +func (rs *ImageStatus) SetCondition(new *ImageCondition) { + if new == nil { + return + } + + t := new.Type + var conditions []ImageCondition + for _, cond := range rs.Conditions { + if cond.Type != t { + conditions = append(conditions, cond) + } else { + // If we'd only update the LastTransitionTime, then return. + new.LastTransitionTime = cond.LastTransitionTime + if reflect.DeepEqual(new, &cond) { + return + } + } + } + new.LastTransitionTime = apis.VolatileTime{metav1.NewTime(time.Now())} + conditions = append(conditions, *new) + // Deterministically order the conditions + sort.Slice(conditions, func(i, j int) bool { return conditions[i].Type < conditions[j].Type }) + rs.Conditions = conditions +} + +func (rs *ImageStatus) InitializeConditions() { + for _, cond := range []ImageConditionType{ + ImageConditionReady, + } { + if rc := rs.GetCondition(cond); rc == nil { + rs.SetCondition(&ImageCondition{ + Type: cond, + Status: corev1.ConditionUnknown, + }) + } + } +} + +func (i *Image) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Image") +} diff --git a/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_validation.go b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_validation.go new file mode 100644 index 00000000..4e644f95 --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/image_validation.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + + "knative.dev/pkg/apis" +) + +func (rt *Image) Validate(ctx context.Context) *apis.FieldError { + return rt.Spec.Validate(ctx).ViaField("spec") +} + +func (rs *ImageSpec) Validate(ctx context.Context) *apis.FieldError { + if rs.Image == "" { + return apis.ErrMissingField("image") + } + // TODO(mattmoor): Consider using go-containerregistry to validate + // the image reference. This is effectively the function we want. + // https://github.com/google/go-containerregistry/blob/2f3e3e1/pkg/name/ref.go#L41 + for index, ips := range rs.ImagePullSecrets { + if equality.Semantic.DeepEqual(ips, corev1.LocalObjectReference{}) { + return apis.ErrMissingField(fmt.Sprintf("imagePullSecrets[%d].name", index)) + } + } + return nil +} diff --git a/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/register.go b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/register.go new file mode 100644 index 00000000..8855fcdf --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "knative.dev/caching/pkg/apis/caching" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: caching.GroupName, Version: "v1alpha1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Image{}, + &ImageList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/zz_generated.deepcopy.go b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..ed87656c --- /dev/null +++ b/vendor/knative.dev/caching/pkg/apis/caching/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,148 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Image) DeepCopyInto(out *Image) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image. +func (in *Image) DeepCopy() *Image { + if in == nil { + return nil + } + out := new(Image) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Image) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageCondition) DeepCopyInto(out *ImageCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageCondition. +func (in *ImageCondition) DeepCopy() *ImageCondition { + if in == nil { + return nil + } + out := new(ImageCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageList) DeepCopyInto(out *ImageList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Image, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageList. +func (in *ImageList) DeepCopy() *ImageList { + if in == nil { + return nil + } + out := new(ImageList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ImageList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageSpec) DeepCopyInto(out *ImageSpec) { + *out = *in + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]v1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageSpec. +func (in *ImageSpec) DeepCopy() *ImageSpec { + if in == nil { + return nil + } + out := new(ImageSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ImageStatus) DeepCopyInto(out *ImageStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]ImageCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageStatus. +func (in *ImageStatus) DeepCopy() *ImageStatus { + if in == nil { + return nil + } + out := new(ImageStatus) + in.DeepCopyInto(out) + return out +}