From c271f4012d0b0127a53ffb626f37315e3c612b69 Mon Sep 17 00:00:00 2001 From: Matt Moore Date: Tue, 30 Jan 2018 14:55:00 -0800 Subject: [PATCH] Incorporate Build into Elafros. This copies over the Build type definitions and generates clients for them. This incorporates BuildSpec into RevisionTemplate and BuildName into Revision. A RevisionTemplate with a BuildSpec will stamp out a Build during reconciliation, and feed the resulting BuildName to the Revision. The Revision will reflect the Build's progress in its Status, and stand up resources upon completion. Fixes: https://github.com/google/elafros/issues/7 --- .bazelrc | 1 + BUILD | 14 +- hack/update-codegen.sh | 2 +- pkg/apis/cloudbuild/BUILD | 8 + pkg/apis/cloudbuild/register.go | 21 + pkg/apis/cloudbuild/v1alpha1/BUILD | 21 + .../v1alpha1/build_template_types.go | 93 ++++ pkg/apis/cloudbuild/v1alpha1/build_types.go | 159 ++++++ pkg/apis/cloudbuild/v1alpha1/doc.go | 21 + pkg/apis/cloudbuild/v1alpha1/register.go | 55 +++ .../v1alpha1/zz_generated.deepcopy.go | 467 ++++++++++++++++++ pkg/apis/ela/v1alpha1/BUILD.bazel | 1 + pkg/apis/ela/v1alpha1/revision_types.go | 11 +- .../ela/v1alpha1/revisiontemplate_types.go | 7 +- .../ela/v1alpha1/zz_generated.deepcopy.go | 10 + pkg/client/clientset/versioned/BUILD.bazel | 1 + pkg/client/clientset/versioned/clientset.go | 26 +- .../clientset/versioned/fake/BUILD.bazel | 3 + .../versioned/fake/clientset_generated.go | 12 + .../clientset/versioned/fake/register.go | 2 + .../clientset/versioned/scheme/BUILD.bazel | 1 + .../clientset/versioned/scheme/register.go | 2 + .../typed/cloudbuild/v1alpha1/BUILD.bazel | 23 + .../typed/cloudbuild/v1alpha1/build.go | 154 ++++++ .../cloudbuild/v1alpha1/buildtemplate.go | 154 ++++++ .../cloudbuild/v1alpha1/cloudbuild_client.go | 92 ++++ .../typed/cloudbuild/v1alpha1/doc.go | 17 + .../cloudbuild/v1alpha1/fake/BUILD.bazel | 24 + .../typed/cloudbuild/v1alpha1/fake/doc.go | 17 + .../cloudbuild/v1alpha1/fake/fake_build.go | 125 +++++ .../v1alpha1/fake/fake_buildtemplate.go | 125 +++++ .../v1alpha1/fake/fake_cloudbuild_client.go | 41 ++ .../v1alpha1/generated_expansion.go | 20 + .../informers/externalversions/BUILD.bazel | 2 + .../externalversions/cloudbuild/BUILD.bazel | 12 + .../externalversions/cloudbuild/interface.go | 46 ++ .../cloudbuild/v1alpha1/BUILD.bazel | 22 + .../cloudbuild/v1alpha1/build.go | 89 ++++ .../cloudbuild/v1alpha1/buildtemplate.go | 89 ++++ .../cloudbuild/v1alpha1/interface.go | 52 ++ .../informers/externalversions/factory.go | 6 + .../informers/externalversions/generic.go | 17 +- .../listers/cloudbuild/v1alpha1/BUILD.bazel | 18 + .../listers/cloudbuild/v1alpha1/build.go | 94 ++++ .../cloudbuild/v1alpha1/buildtemplate.go | 94 ++++ .../v1alpha1/expansion_generated.go | 35 ++ pkg/controller/revision/BUILD.bazel | 2 + pkg/controller/revision/controller.go | 251 +++++++++- pkg/controller/revision/controller_test.go | 297 ++++++++++- pkg/controller/revisiontemplate/BUILD.bazel | 3 + pkg/controller/revisiontemplate/controller.go | 51 +- .../revisiontemplate/controller_test.go | 47 ++ pkg/controller/testing/hooks_test.go | 49 +- sample/revisiontemplate.yaml | 7 + 54 files changed, 2938 insertions(+), 75 deletions(-) create mode 100644 pkg/apis/cloudbuild/BUILD create mode 100644 pkg/apis/cloudbuild/register.go create mode 100644 pkg/apis/cloudbuild/v1alpha1/BUILD create mode 100644 pkg/apis/cloudbuild/v1alpha1/build_template_types.go create mode 100644 pkg/apis/cloudbuild/v1alpha1/build_types.go create mode 100644 pkg/apis/cloudbuild/v1alpha1/doc.go create mode 100644 pkg/apis/cloudbuild/v1alpha1/register.go create mode 100644 pkg/apis/cloudbuild/v1alpha1/zz_generated.deepcopy.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/BUILD.bazel create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/build.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/buildtemplate.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/cloudbuild_client.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/doc.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/BUILD.bazel create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/doc.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_build.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_buildtemplate.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_cloudbuild_client.go create mode 100644 pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/generated_expansion.go create mode 100644 pkg/client/informers/externalversions/cloudbuild/BUILD.bazel create mode 100644 pkg/client/informers/externalversions/cloudbuild/interface.go create mode 100644 pkg/client/informers/externalversions/cloudbuild/v1alpha1/BUILD.bazel create mode 100644 pkg/client/informers/externalversions/cloudbuild/v1alpha1/build.go create mode 100644 pkg/client/informers/externalversions/cloudbuild/v1alpha1/buildtemplate.go create mode 100644 pkg/client/informers/externalversions/cloudbuild/v1alpha1/interface.go create mode 100644 pkg/client/listers/cloudbuild/v1alpha1/BUILD.bazel create mode 100644 pkg/client/listers/cloudbuild/v1alpha1/build.go create mode 100644 pkg/client/listers/cloudbuild/v1alpha1/buildtemplate.go create mode 100644 pkg/client/listers/cloudbuild/v1alpha1/expansion_generated.go diff --git a/.bazelrc b/.bazelrc index 86ab384aa03f..719ef0a42cee 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,2 +1,3 @@ build --workspace_status_command=./print-workspace-status.sh run --workspace_status_command=./print-workspace-status.sh +test --test_output=errors \ No newline at end of file diff --git a/BUILD b/BUILD index 87b749d055fe..4dadf7644519 100644 --- a/BUILD +++ b/BUILD @@ -84,11 +84,10 @@ k8s_objects( ], ) +# All of our stuff goes here. k8s_objects( - name = "everything", + name = "elafros", objects = [ - # We depend on Istio. - ":istio", ":namespace", ":authz", ":crds", @@ -97,3 +96,12 @@ k8s_objects( ":elawebhookservice", ], ) + +k8s_objects( + name = "everything", + objects = [ + ":istio", # We depend on Istio. + # TODO(mattmoor): Add the Build stuff here once we can import it properly. + ":elafros", + ], +) diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index e9e21be89434..a19c235daa9a 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -27,7 +27,7 @@ CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${SCRIPT_ROOT}; ls -d -1 ./vendor/k8s.io/code-ge # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ github.com/google/elafros/pkg/client github.com/google/elafros/pkg/apis \ - "ela:v1alpha1 istio:v1alpha2" \ + "ela:v1alpha1 istio:v1alpha2 cloudbuild:v1alpha1" \ --go-header-file ${SCRIPT_ROOT}/hack/boilerplate/boilerplate.go.txt # Make sure our dependencies are up-to-date diff --git a/pkg/apis/cloudbuild/BUILD b/pkg/apis/cloudbuild/BUILD new file mode 100644 index 000000000000..7edac075dfa1 --- /dev/null +++ b/pkg/apis/cloudbuild/BUILD @@ -0,0 +1,8 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["register.go"], + importpath = "github.com/google/elafros/pkg/apis/cloudbuild", + visibility = ["//visibility:public"], +) diff --git a/pkg/apis/cloudbuild/register.go b/pkg/apis/cloudbuild/register.go new file mode 100644 index 000000000000..b72d3af10115 --- /dev/null +++ b/pkg/apis/cloudbuild/register.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 cloudbuild + +const ( + GroupName = "cloudbuild.googleapis.com" +) diff --git a/pkg/apis/cloudbuild/v1alpha1/BUILD b/pkg/apis/cloudbuild/v1alpha1/BUILD new file mode 100644 index 000000000000..522772a2bfb2 --- /dev/null +++ b/pkg/apis/cloudbuild/v1alpha1/BUILD @@ -0,0 +1,21 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "build_template_types.go", + "build_types.go", + "doc.go", + "register.go", + "zz_generated.deepcopy.go", + ], + importpath = "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/cloudbuild:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + ], +) diff --git a/pkg/apis/cloudbuild/v1alpha1/build_template_types.go b/pkg/apis/cloudbuild/v1alpha1/build_template_types.go new file mode 100644 index 000000000000..9aa936a69ba2 --- /dev/null +++ b/pkg/apis/cloudbuild/v1alpha1/build_template_types.go @@ -0,0 +1,93 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type BuildTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BuildTemplateSpec `json:"spec"` + Status BuildTemplateStatus `json:"status"` +} + +type BuildTemplateSpec struct { + // Parameters defines the parameters that can be populated in a template. + Parameters []ParameterSpec `json:"parameters,omitempty"` + Steps []corev1.Container `json:"steps,omitempty"` + Volumes []corev1.Volume `json:"volumes"` +} + +// BuildTemplateStatus is the status for a Build resource +type BuildTemplateStatus struct { + Conditions []BuildTemplateCondition `json:"conditions,omitempty"` +} + +type BuildTemplateConditionType string + +const ( + // BuildTemplateInvalid specifies that the given specification is invalid. + BuildTemplateInvalid BuildTemplateConditionType = "Invalid" +) + +// BuildTemplateCondition defines a readiness condition for a BuildTemplate. +// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties +type BuildTemplateCondition struct { + Type BuildTemplateConditionType `json:"state"` + + Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` + + // +optional + LastTransitionTime metav1.Time `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"` +} + +// ParameterSpec defines the possible parameters that can be populated in a +// template. +type ParameterSpec struct { + // Name is the unique name of this template parameter. + Name string `json:"name,omitempty"` + + // Description is a human-readable explanation of this template parameter. + Description string `json:"description,omitempty"` + + // Default, if specified, defines the default value that should be applied if + // the build does not specify the value for this parameter. + Default string `json:"default,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// BuildTemplateList is a list of BuildTemplate resources +type BuildTemplateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []BuildTemplate `json:"items"` +} diff --git a/pkg/apis/cloudbuild/v1alpha1/build_types.go b/pkg/apis/cloudbuild/v1alpha1/build_types.go new file mode 100644 index 000000000000..7b87e7c57567 --- /dev/null +++ b/pkg/apis/cloudbuild/v1alpha1/build_types.go @@ -0,0 +1,159 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:noStatus +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Build is a specification for a Build resource +type Build struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BuildSpec `json:"spec"` + Status BuildStatus `json:"status"` +} + +// BuildSpec is the spec for a Build resource +type BuildSpec struct { + Source *SourceSpec `json:"source,omitempty"` + Steps []corev1.Container `json:"steps,omitempty"` + // TODO(mattmoor): Remove Images + Images []string `json:"images,omitempty"` + + Volumes []corev1.Volume `json:"volumes,omitempty"` + + // Template, if specified,references a BuildTemplate resource to use to + // populate fields in the build, and optional Arguments to pass to the + // template. + Template TemplateInstantiationSpec `json:"template,omitempty"` +} + +type TemplateInstantiationSpec struct { + // Name references the BuildTemplate resource to use. + Name string `json:"name,omitempty"` + + // Namespace, if specified, is the namespace of the BuildTemplate resource to + // use. If omitted, the build's namespace is used. + Namespace string `json:"namespace,omitempty"` + + // Arguments, if specified, lists values that should be applied to the + // parameters specified by the template. + Arguments []ArgumentSpec `json:"arguments,omitempty"` +} + +// ArgumentSpec defines the actual values to use to populate a template's +// parameters. +type ArgumentSpec struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` + // TODO(jasonhall): ValueFrom? +} + +// SourceSpec defines the input to the Build +type SourceSpec struct { + Git *GitSourceSpec `json:"git,omitempty"` + Custom *corev1.Container `json:"custom,omitempty"` +} + +type GitSourceSpec struct { + Url string `json:"url"` + + // One of these may be specified. + Branch string `json:"branch,omitempty"` + Tag string `json:"tag,omitempty"` + Ref string `json:"ref,omitempty"` + Commit string `json:"commit,omitempty"` + + // TODO(mattmoor): authn/z +} + +type Builder string + +const ( + // GoogleBuilder indicates that this build was performed with Google Container Builder. + GoogleBuilder Builder = "Google" + // ClusterBuilder indicates that this build was performed on-cluster. + ClusterBuilder Builder = "Cluster" +) + +// BuildStatus is the status for a Build resource +type BuildStatus struct { + Builder Builder `json:"builder,omitempty"` + + // Additional information based on the Builder executing this build. + Cluster *ClusterSpec `json:"cluster,omitempty"` + Google *GoogleSpec `json:"google,omitempty"` + + // Information about the execution of the build. + StartTime metav1.Time `json:"startTime,omitEmpty"` + CompletionTime metav1.Time `json:"completionTime,omitEmpty"` + + Conditions []BuildCondition `json:"conditions,omitempty"` +} + +type ClusterSpec struct { + Namespace string `json:"namespace,omitempty"` + JobName string `json:"jobName,omitempty"` +} + +type GoogleSpec struct { + Operation string `json:"operation,omitempty"` +} + +type BuildConditionType string + +const ( + // BuildComplete specifies that the build has completed successfully. + BuildComplete BuildConditionType = "Complete" + // BuildFailed specifies that the build has failed. + BuildFailed BuildConditionType = "Failed" + // BuildInvalid specifies that the given build specification is invalid. + BuildInvalid BuildConditionType = "Invalid" +) + +// BuildCondition defines a readiness condition for a Build. +// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties +type BuildCondition struct { + Type BuildConditionType `json:"state"` + + Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` + + // +optional + LastTransitionTime metav1.Time `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"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// BuildList is a list of Build resources +type BuildList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Build `json:"items"` +} diff --git a/pkg/apis/cloudbuild/v1alpha1/doc.go b/pkg/apis/cloudbuild/v1alpha1/doc.go new file mode 100644 index 000000000000..e22928705d4b --- /dev/null +++ b/pkg/apis/cloudbuild/v1alpha1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 + +// Package v1alpha1 is the v1alpha1 version of the API. +// +groupName=cloudbuild.googleapis.com +package v1alpha1 diff --git a/pkg/apis/cloudbuild/v1alpha1/register.go b/pkg/apis/cloudbuild/v1alpha1/register.go new file mode 100644 index 000000000000..c9a0b65e4e75 --- /dev/null +++ b/pkg/apis/cloudbuild/v1alpha1/register.go @@ -0,0 +1,55 @@ +/* +Copyright 2018 Google, Inc. All rights reserved. + +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 ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + cloudbuild "github.com/google/elafros/pkg/apis/cloudbuild" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: cloudbuild.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, + &Build{}, + &BuildList{}, + &BuildTemplate{}, + &BuildTemplateList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/cloudbuild/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/cloudbuild/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000000..58283e52a1ee --- /dev/null +++ b/pkg/apis/cloudbuild/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,467 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +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 *ArgumentSpec) DeepCopyInto(out *ArgumentSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgumentSpec. +func (in *ArgumentSpec) DeepCopy() *ArgumentSpec { + if in == nil { + return nil + } + out := new(ArgumentSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Build) DeepCopyInto(out *Build) { + *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 Build. +func (in *Build) DeepCopy() *Build { + if in == nil { + return nil + } + out := new(Build) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Build) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } else { + return nil + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildCondition) DeepCopyInto(out *BuildCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildCondition. +func (in *BuildCondition) DeepCopy() *BuildCondition { + if in == nil { + return nil + } + out := new(BuildCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildList) DeepCopyInto(out *BuildList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Build, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildList. +func (in *BuildList) DeepCopy() *BuildList { + if in == nil { + return nil + } + out := new(BuildList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BuildList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } else { + return nil + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildSpec) DeepCopyInto(out *BuildSpec) { + *out = *in + if in.Source != nil { + in, out := &in.Source, &out.Source + if *in == nil { + *out = nil + } else { + *out = new(SourceSpec) + (*in).DeepCopyInto(*out) + } + } + if in.Steps != nil { + in, out := &in.Steps, &out.Steps + *out = make([]v1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Images != nil { + in, out := &in.Images, &out.Images + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]v1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Template.DeepCopyInto(&out.Template) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildSpec. +func (in *BuildSpec) DeepCopy() *BuildSpec { + if in == nil { + return nil + } + out := new(BuildSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildStatus) DeepCopyInto(out *BuildStatus) { + *out = *in + if in.Cluster != nil { + in, out := &in.Cluster, &out.Cluster + if *in == nil { + *out = nil + } else { + *out = new(ClusterSpec) + **out = **in + } + } + if in.Google != nil { + in, out := &in.Google, &out.Google + if *in == nil { + *out = nil + } else { + *out = new(GoogleSpec) + **out = **in + } + } + in.StartTime.DeepCopyInto(&out.StartTime) + in.CompletionTime.DeepCopyInto(&out.CompletionTime) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]BuildCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildStatus. +func (in *BuildStatus) DeepCopy() *BuildStatus { + if in == nil { + return nil + } + out := new(BuildStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildTemplate) DeepCopyInto(out *BuildTemplate) { + *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 BuildTemplate. +func (in *BuildTemplate) DeepCopy() *BuildTemplate { + if in == nil { + return nil + } + out := new(BuildTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BuildTemplate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } else { + return nil + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildTemplateCondition) DeepCopyInto(out *BuildTemplateCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildTemplateCondition. +func (in *BuildTemplateCondition) DeepCopy() *BuildTemplateCondition { + if in == nil { + return nil + } + out := new(BuildTemplateCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildTemplateList) DeepCopyInto(out *BuildTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BuildTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildTemplateList. +func (in *BuildTemplateList) DeepCopy() *BuildTemplateList { + if in == nil { + return nil + } + out := new(BuildTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BuildTemplateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } else { + return nil + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildTemplateSpec) DeepCopyInto(out *BuildTemplateSpec) { + *out = *in + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = make([]ParameterSpec, len(*in)) + copy(*out, *in) + } + if in.Steps != nil { + in, out := &in.Steps, &out.Steps + *out = make([]v1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]v1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildTemplateSpec. +func (in *BuildTemplateSpec) DeepCopy() *BuildTemplateSpec { + if in == nil { + return nil + } + out := new(BuildTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildTemplateStatus) DeepCopyInto(out *BuildTemplateStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]BuildTemplateCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildTemplateStatus. +func (in *BuildTemplateStatus) DeepCopy() *BuildTemplateStatus { + if in == nil { + return nil + } + out := new(BuildTemplateStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec. +func (in *ClusterSpec) DeepCopy() *ClusterSpec { + if in == nil { + return nil + } + out := new(ClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GitSourceSpec) DeepCopyInto(out *GitSourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitSourceSpec. +func (in *GitSourceSpec) DeepCopy() *GitSourceSpec { + if in == nil { + return nil + } + out := new(GitSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GoogleSpec) DeepCopyInto(out *GoogleSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GoogleSpec. +func (in *GoogleSpec) DeepCopy() *GoogleSpec { + if in == nil { + return nil + } + out := new(GoogleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParameterSpec) DeepCopyInto(out *ParameterSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterSpec. +func (in *ParameterSpec) DeepCopy() *ParameterSpec { + if in == nil { + return nil + } + out := new(ParameterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceSpec) DeepCopyInto(out *SourceSpec) { + *out = *in + if in.Git != nil { + in, out := &in.Git, &out.Git + if *in == nil { + *out = nil + } else { + *out = new(GitSourceSpec) + **out = **in + } + } + if in.Custom != nil { + in, out := &in.Custom, &out.Custom + if *in == nil { + *out = nil + } else { + *out = new(v1.Container) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceSpec. +func (in *SourceSpec) DeepCopy() *SourceSpec { + if in == nil { + return nil + } + out := new(SourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateInstantiationSpec) DeepCopyInto(out *TemplateInstantiationSpec) { + *out = *in + if in.Arguments != nil { + in, out := &in.Arguments, &out.Arguments + *out = make([]ArgumentSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateInstantiationSpec. +func (in *TemplateInstantiationSpec) DeepCopy() *TemplateInstantiationSpec { + if in == nil { + return nil + } + out := new(TemplateInstantiationSpec) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/ela/v1alpha1/BUILD.bazel b/pkg/apis/ela/v1alpha1/BUILD.bazel index f63ed30030ed..d731a91a742a 100644 --- a/pkg/apis/ela/v1alpha1/BUILD.bazel +++ b/pkg/apis/ela/v1alpha1/BUILD.bazel @@ -13,6 +13,7 @@ go_library( importpath = "github.com/google/elafros/pkg/apis/ela/v1alpha1", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/apis/ela/v1alpha1/revision_types.go b/pkg/apis/ela/v1alpha1/revision_types.go index 2435737aad1f..bfdce61f9072 100644 --- a/pkg/apis/ela/v1alpha1/revision_types.go +++ b/pkg/apis/ela/v1alpha1/revision_types.go @@ -61,9 +61,14 @@ type RevisionSpec struct { // as necessary Active bool `json:"active"` - // One of these must be specified - FunctionSpec *FunctionSpec `json:"functionSpec,omitempty"` - AppSpec *AppSpec `json:"appSpec,omitempty"` + // The name of the build that is producing the container image that we are deploying. + BuildName string `json:"buildName,omitempty"` + + // TODO(mattmoor): Remove these, and type definitions above. + FunctionSpec *FunctionSpec `json:"functionSpec,omitempty"` + AppSpec *AppSpec `json:"appSpec,omitempty"` + + // TODO(mattmoor): Change to corev1.Container ContainerSpec *ContainerSpec `json:"containerSpec,omitempty"` // List of environment variables that will be passed to the app container. diff --git a/pkg/apis/ela/v1alpha1/revisiontemplate_types.go b/pkg/apis/ela/v1alpha1/revisiontemplate_types.go index 75e999dcd297..08e77ee72b1e 100644 --- a/pkg/apis/ela/v1alpha1/revisiontemplate_types.go +++ b/pkg/apis/ela/v1alpha1/revisiontemplate_types.go @@ -17,6 +17,8 @@ limitations under the License. package v1alpha1 import ( + build "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -38,8 +40,9 @@ type RevisionTemplateSpec struct { // by the APIserver (https://github.com/kubernetes/kubernetes/issues/58778) // So, we add Generation here. Once that gets fixed, remove this and use // ObjectMeta.Generation instead. - Generation int64 `json:"generation,omitempty"` - Template Revision `json:"template"` + Generation int64 `json:"generation,omitempty"` + Build *build.BuildSpec `json:"build,omitempty"` + Template Revision `json:"template"` } // RevisionTemplateStatus defines the observed state of RevisionTemplate diff --git a/pkg/apis/ela/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/ela/v1alpha1/zz_generated.deepcopy.go index f3b9d64471a1..523297dc442c 100644 --- a/pkg/apis/ela/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/ela/v1alpha1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1alpha1 import ( + cloudbuild_v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -407,6 +408,15 @@ func (in *RevisionTemplateList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RevisionTemplateSpec) DeepCopyInto(out *RevisionTemplateSpec) { *out = *in + if in.Build != nil { + in, out := &in.Build, &out.Build + if *in == nil { + *out = nil + } else { + *out = new(cloudbuild_v1alpha1.BuildSpec) + (*in).DeepCopyInto(*out) + } + } in.Template.DeepCopyInto(&out.Template) return } diff --git a/pkg/client/clientset/versioned/BUILD.bazel b/pkg/client/clientset/versioned/BUILD.bazel index b8eda4b3505b..fed3b00a8e4d 100644 --- a/pkg/client/clientset/versioned/BUILD.bazel +++ b/pkg/client/clientset/versioned/BUILD.bazel @@ -9,6 +9,7 @@ go_library( importpath = "github.com/google/elafros/pkg/client/clientset/versioned", visibility = ["//visibility:public"], deps = [ + "//pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1:go_default_library", "//pkg/client/clientset/versioned/typed/ela/v1alpha1:go_default_library", "//pkg/client/clientset/versioned/typed/istio/v1alpha2:go_default_library", "//vendor/github.com/golang/glog:go_default_library", diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index cee37176d496..cc685aa1e936 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -17,6 +17,7 @@ package versioned import ( glog "github.com/golang/glog" + cloudbuildv1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1" elafrosv1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/ela/v1alpha1" configv1alpha2 "github.com/google/elafros/pkg/client/clientset/versioned/typed/istio/v1alpha2" discovery "k8s.io/client-go/discovery" @@ -26,6 +27,9 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface + CloudbuildV1alpha1() cloudbuildv1alpha1.CloudbuildV1alpha1Interface + // Deprecated: please explicitly pick a version if possible. + Cloudbuild() cloudbuildv1alpha1.CloudbuildV1alpha1Interface ElafrosV1alpha1() elafrosv1alpha1.ElafrosV1alpha1Interface // Deprecated: please explicitly pick a version if possible. Elafros() elafrosv1alpha1.ElafrosV1alpha1Interface @@ -38,8 +42,20 @@ type Interface interface { // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - elafrosV1alpha1 *elafrosv1alpha1.ElafrosV1alpha1Client - configV1alpha2 *configv1alpha2.ConfigV1alpha2Client + cloudbuildV1alpha1 *cloudbuildv1alpha1.CloudbuildV1alpha1Client + elafrosV1alpha1 *elafrosv1alpha1.ElafrosV1alpha1Client + configV1alpha2 *configv1alpha2.ConfigV1alpha2Client +} + +// CloudbuildV1alpha1 retrieves the CloudbuildV1alpha1Client +func (c *Clientset) CloudbuildV1alpha1() cloudbuildv1alpha1.CloudbuildV1alpha1Interface { + return c.cloudbuildV1alpha1 +} + +// Deprecated: Cloudbuild retrieves the default version of CloudbuildClient. +// Please explicitly pick a version. +func (c *Clientset) Cloudbuild() cloudbuildv1alpha1.CloudbuildV1alpha1Interface { + return c.cloudbuildV1alpha1 } // ElafrosV1alpha1 retrieves the ElafrosV1alpha1Client @@ -80,6 +96,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error + cs.cloudbuildV1alpha1, err = cloudbuildv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.elafrosV1alpha1, err = elafrosv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -101,6 +121,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset + cs.cloudbuildV1alpha1 = cloudbuildv1alpha1.NewForConfigOrDie(c) cs.elafrosV1alpha1 = elafrosv1alpha1.NewForConfigOrDie(c) cs.configV1alpha2 = configv1alpha2.NewForConfigOrDie(c) @@ -111,6 +132,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset + cs.cloudbuildV1alpha1 = cloudbuildv1alpha1.New(c) cs.elafrosV1alpha1 = elafrosv1alpha1.New(c) cs.configV1alpha2 = configv1alpha2.New(c) diff --git a/pkg/client/clientset/versioned/fake/BUILD.bazel b/pkg/client/clientset/versioned/fake/BUILD.bazel index 1346158bb5b3..366a0093cee2 100644 --- a/pkg/client/clientset/versioned/fake/BUILD.bazel +++ b/pkg/client/clientset/versioned/fake/BUILD.bazel @@ -10,9 +10,12 @@ go_library( importpath = "github.com/google/elafros/pkg/client/clientset/versioned/fake", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/apis/istio/v1alpha2:go_default_library", "//pkg/client/clientset/versioned:go_default_library", + "//pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1:go_default_library", + "//pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake:go_default_library", "//pkg/client/clientset/versioned/typed/ela/v1alpha1:go_default_library", "//pkg/client/clientset/versioned/typed/ela/v1alpha1/fake:go_default_library", "//pkg/client/clientset/versioned/typed/istio/v1alpha2:go_default_library", diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index e398d84fbfab..e8cb6ad4b690 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -17,6 +17,8 @@ package fake import ( clientset "github.com/google/elafros/pkg/client/clientset/versioned" + cloudbuildv1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1" + fakecloudbuildv1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake" elafrosv1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/ela/v1alpha1" fakeelafrosv1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/ela/v1alpha1/fake" configv1alpha2 "github.com/google/elafros/pkg/client/clientset/versioned/typed/istio/v1alpha2" @@ -61,6 +63,16 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { var _ clientset.Interface = &Clientset{} +// CloudbuildV1alpha1 retrieves the CloudbuildV1alpha1Client +func (c *Clientset) CloudbuildV1alpha1() cloudbuildv1alpha1.CloudbuildV1alpha1Interface { + return &fakecloudbuildv1alpha1.FakeCloudbuildV1alpha1{Fake: &c.Fake} +} + +// Cloudbuild retrieves the CloudbuildV1alpha1Client +func (c *Clientset) Cloudbuild() cloudbuildv1alpha1.CloudbuildV1alpha1Interface { + return &fakecloudbuildv1alpha1.FakeCloudbuildV1alpha1{Fake: &c.Fake} +} + // ElafrosV1alpha1 retrieves the ElafrosV1alpha1Client func (c *Clientset) ElafrosV1alpha1() elafrosv1alpha1.ElafrosV1alpha1Interface { return &fakeelafrosv1alpha1.FakeElafrosV1alpha1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index bc279cc8894a..304ba3bbec76 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -16,6 +16,7 @@ limitations under the License. package fake import ( + cloudbuildv1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" elafrosv1alpha1 "github.com/google/elafros/pkg/apis/ela/v1alpha1" configv1alpha2 "github.com/google/elafros/pkg/apis/istio/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -48,6 +49,7 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { + cloudbuildv1alpha1.AddToScheme(scheme) elafrosv1alpha1.AddToScheme(scheme) configv1alpha2.AddToScheme(scheme) diff --git a/pkg/client/clientset/versioned/scheme/BUILD.bazel b/pkg/client/clientset/versioned/scheme/BUILD.bazel index f0a5954a4920..d5035faa9561 100644 --- a/pkg/client/clientset/versioned/scheme/BUILD.bazel +++ b/pkg/client/clientset/versioned/scheme/BUILD.bazel @@ -9,6 +9,7 @@ go_library( importpath = "github.com/google/elafros/pkg/client/clientset/versioned/scheme", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/apis/istio/v1alpha2:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index d6b47eafd45b..a5ce1b594aac 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -16,6 +16,7 @@ limitations under the License. package scheme import ( + cloudbuildv1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" elafrosv1alpha1 "github.com/google/elafros/pkg/apis/ela/v1alpha1" configv1alpha2 "github.com/google/elafros/pkg/apis/istio/v1alpha2" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -48,6 +49,7 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { + cloudbuildv1alpha1.AddToScheme(scheme) elafrosv1alpha1.AddToScheme(scheme) configv1alpha2.AddToScheme(scheme) diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/BUILD.bazel b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/BUILD.bazel new file mode 100644 index 000000000000..857c14495ae1 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/BUILD.bazel @@ -0,0 +1,23 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "build.go", + "buildtemplate.go", + "cloudbuild_client.go", + "doc.go", + "generated_expansion.go", + ], + importpath = "github.com/google/elafros/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", + "//pkg/client/clientset/versioned/scheme:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", + "//vendor/k8s.io/client-go/rest:go_default_library", + ], +) diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/build.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/build.go new file mode 100644 index 000000000000..bf93b63c0ad1 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/build.go @@ -0,0 +1,154 @@ +/* +Copyright 2018 The Kubernetes 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 ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + scheme "github.com/google/elafros/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// BuildsGetter has a method to return a BuildInterface. +// A group's client should implement this interface. +type BuildsGetter interface { + Builds(namespace string) BuildInterface +} + +// BuildInterface has methods to work with Build resources. +type BuildInterface interface { + Create(*v1alpha1.Build) (*v1alpha1.Build, error) + Update(*v1alpha1.Build) (*v1alpha1.Build, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Build, error) + List(opts v1.ListOptions) (*v1alpha1.BuildList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Build, err error) + BuildExpansion +} + +// builds implements BuildInterface +type builds struct { + client rest.Interface + ns string +} + +// newBuilds returns a Builds +func newBuilds(c *CloudbuildV1alpha1Client, namespace string) *builds { + return &builds{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the build, and returns the corresponding build object, and an error if there is any. +func (c *builds) Get(name string, options v1.GetOptions) (result *v1alpha1.Build, err error) { + result = &v1alpha1.Build{} + err = c.client.Get(). + Namespace(c.ns). + Resource("builds"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Builds that match those selectors. +func (c *builds) List(opts v1.ListOptions) (result *v1alpha1.BuildList, err error) { + result = &v1alpha1.BuildList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("builds"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested builds. +func (c *builds) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("builds"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a build and creates it. Returns the server's representation of the build, and an error, if there is any. +func (c *builds) Create(build *v1alpha1.Build) (result *v1alpha1.Build, err error) { + result = &v1alpha1.Build{} + err = c.client.Post(). + Namespace(c.ns). + Resource("builds"). + Body(build). + Do(). + Into(result) + return +} + +// Update takes the representation of a build and updates it. Returns the server's representation of the build, and an error, if there is any. +func (c *builds) Update(build *v1alpha1.Build) (result *v1alpha1.Build, err error) { + result = &v1alpha1.Build{} + err = c.client.Put(). + Namespace(c.ns). + Resource("builds"). + Name(build.Name). + Body(build). + Do(). + Into(result) + return +} + +// Delete takes name of the build and deletes it. Returns an error if one occurs. +func (c *builds) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("builds"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *builds) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("builds"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched build. +func (c *builds) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Build, err error) { + result = &v1alpha1.Build{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("builds"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/buildtemplate.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/buildtemplate.go new file mode 100644 index 000000000000..087447c74c80 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/buildtemplate.go @@ -0,0 +1,154 @@ +/* +Copyright 2018 The Kubernetes 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 ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + scheme "github.com/google/elafros/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// BuildTemplatesGetter has a method to return a BuildTemplateInterface. +// A group's client should implement this interface. +type BuildTemplatesGetter interface { + BuildTemplates(namespace string) BuildTemplateInterface +} + +// BuildTemplateInterface has methods to work with BuildTemplate resources. +type BuildTemplateInterface interface { + Create(*v1alpha1.BuildTemplate) (*v1alpha1.BuildTemplate, error) + Update(*v1alpha1.BuildTemplate) (*v1alpha1.BuildTemplate, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.BuildTemplate, error) + List(opts v1.ListOptions) (*v1alpha1.BuildTemplateList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.BuildTemplate, err error) + BuildTemplateExpansion +} + +// buildTemplates implements BuildTemplateInterface +type buildTemplates struct { + client rest.Interface + ns string +} + +// newBuildTemplates returns a BuildTemplates +func newBuildTemplates(c *CloudbuildV1alpha1Client, namespace string) *buildTemplates { + return &buildTemplates{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the buildTemplate, and returns the corresponding buildTemplate object, and an error if there is any. +func (c *buildTemplates) Get(name string, options v1.GetOptions) (result *v1alpha1.BuildTemplate, err error) { + result = &v1alpha1.BuildTemplate{} + err = c.client.Get(). + Namespace(c.ns). + Resource("buildtemplates"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of BuildTemplates that match those selectors. +func (c *buildTemplates) List(opts v1.ListOptions) (result *v1alpha1.BuildTemplateList, err error) { + result = &v1alpha1.BuildTemplateList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("buildtemplates"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested buildTemplates. +func (c *buildTemplates) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("buildtemplates"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a buildTemplate and creates it. Returns the server's representation of the buildTemplate, and an error, if there is any. +func (c *buildTemplates) Create(buildTemplate *v1alpha1.BuildTemplate) (result *v1alpha1.BuildTemplate, err error) { + result = &v1alpha1.BuildTemplate{} + err = c.client.Post(). + Namespace(c.ns). + Resource("buildtemplates"). + Body(buildTemplate). + Do(). + Into(result) + return +} + +// Update takes the representation of a buildTemplate and updates it. Returns the server's representation of the buildTemplate, and an error, if there is any. +func (c *buildTemplates) Update(buildTemplate *v1alpha1.BuildTemplate) (result *v1alpha1.BuildTemplate, err error) { + result = &v1alpha1.BuildTemplate{} + err = c.client.Put(). + Namespace(c.ns). + Resource("buildtemplates"). + Name(buildTemplate.Name). + Body(buildTemplate). + Do(). + Into(result) + return +} + +// Delete takes name of the buildTemplate and deletes it. Returns an error if one occurs. +func (c *buildTemplates) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("buildtemplates"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *buildTemplates) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("buildtemplates"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched buildTemplate. +func (c *buildTemplates) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.BuildTemplate, err error) { + result = &v1alpha1.BuildTemplate{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("buildtemplates"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/cloudbuild_client.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/cloudbuild_client.go new file mode 100644 index 000000000000..3a66a1c402ab --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/cloudbuild_client.go @@ -0,0 +1,92 @@ +/* +Copyright 2018 The Kubernetes 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 ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + "github.com/google/elafros/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type CloudbuildV1alpha1Interface interface { + RESTClient() rest.Interface + BuildsGetter + BuildTemplatesGetter +} + +// CloudbuildV1alpha1Client is used to interact with features provided by the cloudbuild.googleapis.com group. +type CloudbuildV1alpha1Client struct { + restClient rest.Interface +} + +func (c *CloudbuildV1alpha1Client) Builds(namespace string) BuildInterface { + return newBuilds(c, namespace) +} + +func (c *CloudbuildV1alpha1Client) BuildTemplates(namespace string) BuildTemplateInterface { + return newBuildTemplates(c, namespace) +} + +// NewForConfig creates a new CloudbuildV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*CloudbuildV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &CloudbuildV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new CloudbuildV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *CloudbuildV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new CloudbuildV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *CloudbuildV1alpha1Client { + return &CloudbuildV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *CloudbuildV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/doc.go new file mode 100644 index 000000000000..232e946cecbd --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/BUILD.bazel b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/BUILD.bazel new file mode 100644 index 000000000000..720ee3f6a2c3 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/BUILD.bazel @@ -0,0 +1,24 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "fake_build.go", + "fake_buildtemplate.go", + "fake_cloudbuild_client.go", + ], + importpath = "github.com/google/elafros/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", + "//pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", + "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/testing:go_default_library", + ], +) diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/doc.go new file mode 100644 index 000000000000..a66e8b1134c2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2018 The Kubernetes 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 fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_build.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_build.go new file mode 100644 index 000000000000..18afdbe0f567 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_build.go @@ -0,0 +1,125 @@ +/* +Copyright 2018 The Kubernetes 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 fake + +import ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeBuilds implements BuildInterface +type FakeBuilds struct { + Fake *FakeCloudbuildV1alpha1 + ns string +} + +var buildsResource = schema.GroupVersionResource{Group: "cloudbuild.googleapis.com", Version: "v1alpha1", Resource: "builds"} + +var buildsKind = schema.GroupVersionKind{Group: "cloudbuild.googleapis.com", Version: "v1alpha1", Kind: "Build"} + +// Get takes name of the build, and returns the corresponding build object, and an error if there is any. +func (c *FakeBuilds) Get(name string, options v1.GetOptions) (result *v1alpha1.Build, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(buildsResource, c.ns, name), &v1alpha1.Build{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Build), err +} + +// List takes label and field selectors, and returns the list of Builds that match those selectors. +func (c *FakeBuilds) List(opts v1.ListOptions) (result *v1alpha1.BuildList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(buildsResource, buildsKind, c.ns, opts), &v1alpha1.BuildList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.BuildList{} + for _, item := range obj.(*v1alpha1.BuildList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested builds. +func (c *FakeBuilds) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(buildsResource, c.ns, opts)) + +} + +// Create takes the representation of a build and creates it. Returns the server's representation of the build, and an error, if there is any. +func (c *FakeBuilds) Create(build *v1alpha1.Build) (result *v1alpha1.Build, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(buildsResource, c.ns, build), &v1alpha1.Build{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Build), err +} + +// Update takes the representation of a build and updates it. Returns the server's representation of the build, and an error, if there is any. +func (c *FakeBuilds) Update(build *v1alpha1.Build) (result *v1alpha1.Build, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(buildsResource, c.ns, build), &v1alpha1.Build{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Build), err +} + +// Delete takes name of the build and deletes it. Returns an error if one occurs. +func (c *FakeBuilds) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(buildsResource, c.ns, name), &v1alpha1.Build{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBuilds) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(buildsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.BuildList{}) + return err +} + +// Patch applies the patch and returns the patched build. +func (c *FakeBuilds) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Build, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(buildsResource, c.ns, name, data, subresources...), &v1alpha1.Build{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Build), err +} diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_buildtemplate.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_buildtemplate.go new file mode 100644 index 000000000000..ba6799b5c5d2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_buildtemplate.go @@ -0,0 +1,125 @@ +/* +Copyright 2018 The Kubernetes 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 fake + +import ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeBuildTemplates implements BuildTemplateInterface +type FakeBuildTemplates struct { + Fake *FakeCloudbuildV1alpha1 + ns string +} + +var buildtemplatesResource = schema.GroupVersionResource{Group: "cloudbuild.googleapis.com", Version: "v1alpha1", Resource: "buildtemplates"} + +var buildtemplatesKind = schema.GroupVersionKind{Group: "cloudbuild.googleapis.com", Version: "v1alpha1", Kind: "BuildTemplate"} + +// Get takes name of the buildTemplate, and returns the corresponding buildTemplate object, and an error if there is any. +func (c *FakeBuildTemplates) Get(name string, options v1.GetOptions) (result *v1alpha1.BuildTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(buildtemplatesResource, c.ns, name), &v1alpha1.BuildTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BuildTemplate), err +} + +// List takes label and field selectors, and returns the list of BuildTemplates that match those selectors. +func (c *FakeBuildTemplates) List(opts v1.ListOptions) (result *v1alpha1.BuildTemplateList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(buildtemplatesResource, buildtemplatesKind, c.ns, opts), &v1alpha1.BuildTemplateList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.BuildTemplateList{} + for _, item := range obj.(*v1alpha1.BuildTemplateList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested buildTemplates. +func (c *FakeBuildTemplates) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(buildtemplatesResource, c.ns, opts)) + +} + +// Create takes the representation of a buildTemplate and creates it. Returns the server's representation of the buildTemplate, and an error, if there is any. +func (c *FakeBuildTemplates) Create(buildTemplate *v1alpha1.BuildTemplate) (result *v1alpha1.BuildTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(buildtemplatesResource, c.ns, buildTemplate), &v1alpha1.BuildTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BuildTemplate), err +} + +// Update takes the representation of a buildTemplate and updates it. Returns the server's representation of the buildTemplate, and an error, if there is any. +func (c *FakeBuildTemplates) Update(buildTemplate *v1alpha1.BuildTemplate) (result *v1alpha1.BuildTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(buildtemplatesResource, c.ns, buildTemplate), &v1alpha1.BuildTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BuildTemplate), err +} + +// Delete takes name of the buildTemplate and deletes it. Returns an error if one occurs. +func (c *FakeBuildTemplates) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(buildtemplatesResource, c.ns, name), &v1alpha1.BuildTemplate{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBuildTemplates) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(buildtemplatesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.BuildTemplateList{}) + return err +} + +// Patch applies the patch and returns the patched buildTemplate. +func (c *FakeBuildTemplates) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.BuildTemplate, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(buildtemplatesResource, c.ns, name, data, subresources...), &v1alpha1.BuildTemplate{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.BuildTemplate), err +} diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_cloudbuild_client.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_cloudbuild_client.go new file mode 100644 index 000000000000..fab66c878478 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/fake/fake_cloudbuild_client.go @@ -0,0 +1,41 @@ +/* +Copyright 2018 The Kubernetes 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 fake + +import ( + v1alpha1 "github.com/google/elafros/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeCloudbuildV1alpha1 struct { + *testing.Fake +} + +func (c *FakeCloudbuildV1alpha1) Builds(namespace string) v1alpha1.BuildInterface { + return &FakeBuilds{c, namespace} +} + +func (c *FakeCloudbuildV1alpha1) BuildTemplates(namespace string) v1alpha1.BuildTemplateInterface { + return &FakeBuildTemplates{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeCloudbuildV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/generated_expansion.go new file mode 100644 index 000000000000..e445bea6ae0d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/cloudbuild/v1alpha1/generated_expansion.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes 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 + +type BuildExpansion interface{} + +type BuildTemplateExpansion interface{} diff --git a/pkg/client/informers/externalversions/BUILD.bazel b/pkg/client/informers/externalversions/BUILD.bazel index c4d5b4188b8b..0b99be3116e8 100644 --- a/pkg/client/informers/externalversions/BUILD.bazel +++ b/pkg/client/informers/externalversions/BUILD.bazel @@ -9,9 +9,11 @@ go_library( importpath = "github.com/google/elafros/pkg/client/informers/externalversions", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/apis/istio/v1alpha2:go_default_library", "//pkg/client/clientset/versioned:go_default_library", + "//pkg/client/informers/externalversions/cloudbuild:go_default_library", "//pkg/client/informers/externalversions/ela:go_default_library", "//pkg/client/informers/externalversions/internalinterfaces:go_default_library", "//pkg/client/informers/externalversions/istio:go_default_library", diff --git a/pkg/client/informers/externalversions/cloudbuild/BUILD.bazel b/pkg/client/informers/externalversions/cloudbuild/BUILD.bazel new file mode 100644 index 000000000000..b6c07bd2648f --- /dev/null +++ b/pkg/client/informers/externalversions/cloudbuild/BUILD.bazel @@ -0,0 +1,12 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["interface.go"], + importpath = "github.com/google/elafros/pkg/client/informers/externalversions/cloudbuild", + visibility = ["//visibility:public"], + deps = [ + "//pkg/client/informers/externalversions/cloudbuild/v1alpha1:go_default_library", + "//pkg/client/informers/externalversions/internalinterfaces:go_default_library", + ], +) diff --git a/pkg/client/informers/externalversions/cloudbuild/interface.go b/pkg/client/informers/externalversions/cloudbuild/interface.go new file mode 100644 index 000000000000..813a871e43c4 --- /dev/null +++ b/pkg/client/informers/externalversions/cloudbuild/interface.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by informer-gen + +package cloudbuild + +import ( + v1alpha1 "github.com/google/elafros/pkg/client/informers/externalversions/cloudbuild/v1alpha1" + internalinterfaces "github.com/google/elafros/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/cloudbuild/v1alpha1/BUILD.bazel b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/BUILD.bazel new file mode 100644 index 000000000000..b29d3464a532 --- /dev/null +++ b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/BUILD.bazel @@ -0,0 +1,22 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "build.go", + "buildtemplate.go", + "interface.go", + ], + importpath = "github.com/google/elafros/pkg/client/informers/externalversions/cloudbuild/v1alpha1", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", + "//pkg/client/clientset/versioned:go_default_library", + "//pkg/client/informers/externalversions/internalinterfaces:go_default_library", + "//pkg/client/listers/cloudbuild/v1alpha1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", + "//vendor/k8s.io/client-go/tools/cache:go_default_library", + ], +) diff --git a/pkg/client/informers/externalversions/cloudbuild/v1alpha1/build.go b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/build.go new file mode 100644 index 000000000000..69f84a27dcaa --- /dev/null +++ b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/build.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by informer-gen + +package v1alpha1 + +import ( + time "time" + + cloudbuild_v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + versioned "github.com/google/elafros/pkg/client/clientset/versioned" + internalinterfaces "github.com/google/elafros/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/google/elafros/pkg/client/listers/cloudbuild/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// BuildInformer provides access to a shared informer and lister for +// Builds. +type BuildInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.BuildLister +} + +type buildInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewBuildInformer constructs a new informer for Build type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBuildInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBuildInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredBuildInformer constructs a new informer for Build type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBuildInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CloudbuildV1alpha1().Builds(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CloudbuildV1alpha1().Builds(namespace).Watch(options) + }, + }, + &cloudbuild_v1alpha1.Build{}, + resyncPeriod, + indexers, + ) +} + +func (f *buildInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBuildInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *buildInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&cloudbuild_v1alpha1.Build{}, f.defaultInformer) +} + +func (f *buildInformer) Lister() v1alpha1.BuildLister { + return v1alpha1.NewBuildLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/cloudbuild/v1alpha1/buildtemplate.go b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/buildtemplate.go new file mode 100644 index 000000000000..1ba062302e04 --- /dev/null +++ b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/buildtemplate.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by informer-gen + +package v1alpha1 + +import ( + time "time" + + cloudbuild_v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + versioned "github.com/google/elafros/pkg/client/clientset/versioned" + internalinterfaces "github.com/google/elafros/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/google/elafros/pkg/client/listers/cloudbuild/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// BuildTemplateInformer provides access to a shared informer and lister for +// BuildTemplates. +type BuildTemplateInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.BuildTemplateLister +} + +type buildTemplateInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewBuildTemplateInformer constructs a new informer for BuildTemplate type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBuildTemplateInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBuildTemplateInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredBuildTemplateInformer constructs a new informer for BuildTemplate type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBuildTemplateInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CloudbuildV1alpha1().BuildTemplates(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CloudbuildV1alpha1().BuildTemplates(namespace).Watch(options) + }, + }, + &cloudbuild_v1alpha1.BuildTemplate{}, + resyncPeriod, + indexers, + ) +} + +func (f *buildTemplateInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBuildTemplateInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *buildTemplateInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&cloudbuild_v1alpha1.BuildTemplate{}, f.defaultInformer) +} + +func (f *buildTemplateInformer) Lister() v1alpha1.BuildTemplateLister { + return v1alpha1.NewBuildTemplateLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/cloudbuild/v1alpha1/interface.go b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/interface.go new file mode 100644 index 000000000000..5672f95b765f --- /dev/null +++ b/pkg/client/informers/externalversions/cloudbuild/v1alpha1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by informer-gen + +package v1alpha1 + +import ( + internalinterfaces "github.com/google/elafros/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Builds returns a BuildInformer. + Builds() BuildInformer + // BuildTemplates returns a BuildTemplateInformer. + BuildTemplates() BuildTemplateInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Builds returns a BuildInformer. +func (v *version) Builds() BuildInformer { + return &buildInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// BuildTemplates returns a BuildTemplateInformer. +func (v *version) BuildTemplates() BuildTemplateInformer { + return &buildTemplateInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 6cc00877f33d..dec15328fd1d 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -24,6 +24,7 @@ import ( time "time" versioned "github.com/google/elafros/pkg/client/clientset/versioned" + cloudbuild "github.com/google/elafros/pkg/client/informers/externalversions/cloudbuild" ela "github.com/google/elafros/pkg/client/informers/externalversions/ela" internalinterfaces "github.com/google/elafros/pkg/client/informers/externalversions/internalinterfaces" istio "github.com/google/elafros/pkg/client/informers/externalversions/istio" @@ -124,10 +125,15 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + Cloudbuild() cloudbuild.Interface Elafros() ela.Interface Config() istio.Interface } +func (f *sharedInformerFactory) Cloudbuild() cloudbuild.Interface { + return cloudbuild.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Elafros() ela.Interface { return ela.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index b814917c08ff..23364c38bb0b 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -21,7 +21,8 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/google/elafros/pkg/apis/ela/v1alpha1" + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + ela_v1alpha1 "github.com/google/elafros/pkg/apis/ela/v1alpha1" v1alpha2 "github.com/google/elafros/pkg/apis/istio/v1alpha2" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" @@ -53,16 +54,22 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=config.istio.io, Version=v1alpha2 + // Group=cloudbuild.googleapis.com, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("builds"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Cloudbuild().V1alpha1().Builds().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("buildtemplates"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Cloudbuild().V1alpha1().BuildTemplates().Informer()}, nil + + // Group=config.istio.io, Version=v1alpha2 case v1alpha2.SchemeGroupVersion.WithResource("routerules"): return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha2().RouteRules().Informer()}, nil // Group=elafros.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("elaservices"): + case ela_v1alpha1.SchemeGroupVersion.WithResource("elaservices"): return &genericInformer{resource: resource.GroupResource(), informer: f.Elafros().V1alpha1().ElaServices().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("revisions"): + case ela_v1alpha1.SchemeGroupVersion.WithResource("revisions"): return &genericInformer{resource: resource.GroupResource(), informer: f.Elafros().V1alpha1().Revisions().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("revisiontemplates"): + case ela_v1alpha1.SchemeGroupVersion.WithResource("revisiontemplates"): return &genericInformer{resource: resource.GroupResource(), informer: f.Elafros().V1alpha1().RevisionTemplates().Informer()}, nil } diff --git a/pkg/client/listers/cloudbuild/v1alpha1/BUILD.bazel b/pkg/client/listers/cloudbuild/v1alpha1/BUILD.bazel new file mode 100644 index 000000000000..12e50aeacfdf --- /dev/null +++ b/pkg/client/listers/cloudbuild/v1alpha1/BUILD.bazel @@ -0,0 +1,18 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "build.go", + "buildtemplate.go", + "expansion_generated.go", + ], + importpath = "github.com/google/elafros/pkg/client/listers/cloudbuild/v1alpha1", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", + "//vendor/k8s.io/client-go/tools/cache:go_default_library", + ], +) diff --git a/pkg/client/listers/cloudbuild/v1alpha1/build.go b/pkg/client/listers/cloudbuild/v1alpha1/build.go new file mode 100644 index 000000000000..6ce0accd4061 --- /dev/null +++ b/pkg/client/listers/cloudbuild/v1alpha1/build.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by lister-gen + +package v1alpha1 + +import ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// BuildLister helps list Builds. +type BuildLister interface { + // List lists all Builds in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Build, err error) + // Builds returns an object that can list and get Builds. + Builds(namespace string) BuildNamespaceLister + BuildListerExpansion +} + +// buildLister implements the BuildLister interface. +type buildLister struct { + indexer cache.Indexer +} + +// NewBuildLister returns a new BuildLister. +func NewBuildLister(indexer cache.Indexer) BuildLister { + return &buildLister{indexer: indexer} +} + +// List lists all Builds in the indexer. +func (s *buildLister) List(selector labels.Selector) (ret []*v1alpha1.Build, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Build)) + }) + return ret, err +} + +// Builds returns an object that can list and get Builds. +func (s *buildLister) Builds(namespace string) BuildNamespaceLister { + return buildNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// BuildNamespaceLister helps list and get Builds. +type BuildNamespaceLister interface { + // List lists all Builds in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Build, err error) + // Get retrieves the Build from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Build, error) + BuildNamespaceListerExpansion +} + +// buildNamespaceLister implements the BuildNamespaceLister +// interface. +type buildNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Builds in the indexer for a given namespace. +func (s buildNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Build, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Build)) + }) + return ret, err +} + +// Get retrieves the Build from the indexer for a given namespace and name. +func (s buildNamespaceLister) Get(name string) (*v1alpha1.Build, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("build"), name) + } + return obj.(*v1alpha1.Build), nil +} diff --git a/pkg/client/listers/cloudbuild/v1alpha1/buildtemplate.go b/pkg/client/listers/cloudbuild/v1alpha1/buildtemplate.go new file mode 100644 index 000000000000..0b47efa16dc6 --- /dev/null +++ b/pkg/client/listers/cloudbuild/v1alpha1/buildtemplate.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by lister-gen + +package v1alpha1 + +import ( + v1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// BuildTemplateLister helps list BuildTemplates. +type BuildTemplateLister interface { + // List lists all BuildTemplates in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.BuildTemplate, err error) + // BuildTemplates returns an object that can list and get BuildTemplates. + BuildTemplates(namespace string) BuildTemplateNamespaceLister + BuildTemplateListerExpansion +} + +// buildTemplateLister implements the BuildTemplateLister interface. +type buildTemplateLister struct { + indexer cache.Indexer +} + +// NewBuildTemplateLister returns a new BuildTemplateLister. +func NewBuildTemplateLister(indexer cache.Indexer) BuildTemplateLister { + return &buildTemplateLister{indexer: indexer} +} + +// List lists all BuildTemplates in the indexer. +func (s *buildTemplateLister) List(selector labels.Selector) (ret []*v1alpha1.BuildTemplate, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.BuildTemplate)) + }) + return ret, err +} + +// BuildTemplates returns an object that can list and get BuildTemplates. +func (s *buildTemplateLister) BuildTemplates(namespace string) BuildTemplateNamespaceLister { + return buildTemplateNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// BuildTemplateNamespaceLister helps list and get BuildTemplates. +type BuildTemplateNamespaceLister interface { + // List lists all BuildTemplates in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.BuildTemplate, err error) + // Get retrieves the BuildTemplate from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.BuildTemplate, error) + BuildTemplateNamespaceListerExpansion +} + +// buildTemplateNamespaceLister implements the BuildTemplateNamespaceLister +// interface. +type buildTemplateNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all BuildTemplates in the indexer for a given namespace. +func (s buildTemplateNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.BuildTemplate, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.BuildTemplate)) + }) + return ret, err +} + +// Get retrieves the BuildTemplate from the indexer for a given namespace and name. +func (s buildTemplateNamespaceLister) Get(name string) (*v1alpha1.BuildTemplate, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("buildtemplate"), name) + } + return obj.(*v1alpha1.BuildTemplate), nil +} diff --git a/pkg/client/listers/cloudbuild/v1alpha1/expansion_generated.go b/pkg/client/listers/cloudbuild/v1alpha1/expansion_generated.go new file mode 100644 index 000000000000..c9e833f97307 --- /dev/null +++ b/pkg/client/listers/cloudbuild/v1alpha1/expansion_generated.go @@ -0,0 +1,35 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// This file was automatically generated by lister-gen + +package v1alpha1 + +// BuildListerExpansion allows custom methods to be added to +// BuildLister. +type BuildListerExpansion interface{} + +// BuildNamespaceListerExpansion allows custom methods to be added to +// BuildNamespaceLister. +type BuildNamespaceListerExpansion interface{} + +// BuildTemplateListerExpansion allows custom methods to be added to +// BuildTemplateLister. +type BuildTemplateListerExpansion interface{} + +// BuildTemplateNamespaceListerExpansion allows custom methods to be added to +// BuildTemplateNamespaceLister. +type BuildTemplateNamespaceListerExpansion interface{} diff --git a/pkg/controller/revision/BUILD.bazel b/pkg/controller/revision/BUILD.bazel index fd327c917a56..8fea326c824f 100644 --- a/pkg/controller/revision/BUILD.bazel +++ b/pkg/controller/revision/BUILD.bazel @@ -13,6 +13,7 @@ go_library( importpath = "github.com/google/elafros/pkg/controller/revision", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/client/clientset/versioned:go_default_library", "//pkg/client/clientset/versioned/scheme:go_default_library", @@ -48,6 +49,7 @@ go_test( embed = [":go_default_library"], importpath = "github.com/google/elafros/pkg/controller/revision", deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/client/clientset/versioned/fake:go_default_library", "//pkg/client/informers/externalversions:go_default_library", diff --git a/pkg/controller/revision/controller.go b/pkg/controller/revision/controller.go index 7aa21231afc0..e6f13b924393 100644 --- a/pkg/controller/revision/controller.go +++ b/pkg/controller/revision/controller.go @@ -19,6 +19,8 @@ package revision import ( "fmt" "log" + "strings" + "sync" "time" "github.com/golang/glog" @@ -39,6 +41,7 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" + buildv1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" "github.com/google/elafros/pkg/apis/ela/v1alpha1" clientset "github.com/google/elafros/pkg/client/clientset/versioned" elascheme "github.com/google/elafros/pkg/client/clientset/versioned/scheme" @@ -48,7 +51,7 @@ import ( "github.com/google/elafros/pkg/controller/util" ) -var controllerKind = v1alpha1.SchemeGroupVersion.WithKind("ElaDeployment") +var controllerKind = v1alpha1.SchemeGroupVersion.WithKind("Revision") const ( elaServiceLabel string = "elaservice" @@ -92,6 +95,35 @@ func printErr(err error) error { return err } +type key string + +func getKey(namespace, name string) key { + return key(fmt.Sprintf("%s/%s", namespace, name)) +} + +func splitKey(k key) (string, string) { + parts := strings.Split(string(k), "/") + if len(parts) != 2 { + panic("key type invariant violated.") + } + return parts[0], parts[1] +} + +type set map[key]struct{} + +func (s set) add(k key) { + s[k] = struct{}{} +} + +func (s set) remove(k key) { + delete(s, k) +} + +func (s set) has(k key) bool { + _, ok := s[k] + return ok +} + // +controller:group=ela,version=v1alpha1,kind=Revision,resource=revisions type RevisionControllerImpl struct { // kubeClient allows us to talk to the k8s for core APIs @@ -113,6 +145,11 @@ type RevisionControllerImpl struct { // recorder is an event recorder for recording Event resources to the // Kubernetes API. recorder record.EventRecorder + + // buildMtx guards modifications to builds + buildMtx sync.Mutex + // The collection of outstanding builds and the sets of revisions waiting for them. + builds map[key]set } // Init initializes the controller and is called by the generated code @@ -143,12 +180,13 @@ func NewController( recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) controller := &RevisionControllerImpl{ - kubeclientset: kubeclientset, - elaclientset: elaclientset, - lister: informer.Lister(), - synced: informer.Informer().HasSynced, - workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Revisions"), - recorder: recorder, + kubeclientset: kubeclientset, + elaclientset: elaclientset, + lister: informer.Lister(), + synced: informer.Informer().HasSynced, + workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Revisions"), + recorder: recorder, + builds: map[key]set{}, } glog.Info("Setting up event handlers") @@ -160,6 +198,13 @@ func NewController( }, }) + // Obtain a reference to a shared index informer for the Build type. + buildInformer := elaInformerFactory.Cloudbuild().V1alpha1().Builds() + buildInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: controller.addBuildEvent, + UpdateFunc: controller.updateBuildEvent, + }) + return controller } @@ -296,6 +341,20 @@ func (c *RevisionControllerImpl) syncHandler(key string) error { } return err } + // Don't modify the informer's copy. + rev = rev.DeepCopy() + + if rev.Spec.BuildName != "" { + if done, failed := isBuildDone(rev); !done { + return c.trackBuild(rev) + } else { + // The Build's complete, so stop tracking it, and keep going. + c.untrackBuild(rev) + if failed { + return nil + } + } + } ns, err := util.GetOrCreateRevisionNamespace(namespace, c.kubeclientset) if err != nil { @@ -309,6 +368,147 @@ func (c *RevisionControllerImpl) syncHandler(key string) error { // reconcileWithImage handles enqueued messages that have an image. func (c *RevisionControllerImpl) reconcileWithImage(u *v1alpha1.Revision, ns string) error { + return printErr(c.reconcileOnceBuilt(u, ns)) +} + +// Checks whether the Revision knows whether the build is done. +func isBuildDone(u *v1alpha1.Revision) (done, failed bool) { + for _, cond := range u.Status.Conditions { + if cond.Status != "True" { + continue + } + switch cond.Type { + case "BuildComplete": + return true, false + case "BuildFailed": + return true, true + } + } + return false, false +} + +func (c *RevisionControllerImpl) trackBuild(u *v1alpha1.Revision) error { + c.buildMtx.Lock() + defer c.buildMtx.Unlock() + + // When this build is complete, mark this revision as ready. + bk := getKey(u.Namespace, u.Spec.BuildName) + entry, ok := c.builds[bk] + if !ok { + entry = set{} + } + k := getKey(u.Namespace, u.Name) + if _, ok := entry[k]; ok { + // Already tracked. + return nil + } + + entry.add(k) + c.builds[bk] = entry + + setCondition(u, "BuildComplete", &v1alpha1.RevisionCondition{ + Type: "BuildComplete", + Status: "False", + Reason: "Building", + }) + // Let this trigger a reconciliation loop. + if _, err := c.updateStatus(u); err != nil { + glog.Errorf("Error recording the BuildComplete=False condition: %s", err) + return err + } + return nil +} + +func (c *RevisionControllerImpl) untrackBuild(u *v1alpha1.Revision) { + c.buildMtx.Lock() + defer c.buildMtx.Unlock() + + // When this build is complete, mark this revision as ready. + bk := getKey(u.Namespace, u.Spec.BuildName) + entry, ok := c.builds[bk] + if ok { + if len(entry) == 0 { + delete(c.builds, bk) + } else { + entry.remove(getKey(u.Namespace, u.Name)) + c.builds[bk] = entry + } + } +} + +func (c *RevisionControllerImpl) markBuildComplete(u *v1alpha1.Revision, bc *buildv1alpha1.BuildCondition) error { + switch bc.Type { + case buildv1alpha1.BuildComplete: + setCondition(u, "BuildFailed", nil) + setCondition(u, "BuildComplete", &v1alpha1.RevisionCondition{ + Type: "BuildComplete", + Status: "True", + }) + case buildv1alpha1.BuildFailed, buildv1alpha1.BuildInvalid: + setCondition(u, "BuildComplete", nil) + setCondition(u, "BuildFailed", &v1alpha1.RevisionCondition{ + Type: "BuildFailed", + Status: "True", + Reason: bc.Reason, + Message: bc.Message, + }) + } + // This will trigger a reconciliation that will cause us to stop tracking the build. + _, err := c.updateStatus(u) + return err +} + +func getBuildDoneCondition(build *buildv1alpha1.Build) *buildv1alpha1.BuildCondition { + for _, cond := range build.Status.Conditions { + if cond.Status != corev1.ConditionTrue { + continue + } + switch cond.Type { + case buildv1alpha1.BuildComplete, buildv1alpha1.BuildFailed, buildv1alpha1.BuildInvalid: + return &cond + } + } + return nil +} + +func (c *RevisionControllerImpl) addBuildEvent(obj interface{}) { + build := obj.(*buildv1alpha1.Build) + + cond := getBuildDoneCondition(build) + if cond == nil { + // The build isn't done, so ignore this event. + return + } + + s, ok := c.builds[getKey(build.Namespace, build.Name)] + if !ok { + // Nothing is watching this build, so ignore this event. + return + } + + // For each of the revisions watching this build, mark their build phase as complete. + for k := range s { + go func(k key) { + // Look up the revision to mark complete. + namespace, name := splitKey(k) + hr, err := c.lister.Revisions(namespace).Get(name) + if err != nil { + glog.Errorf("Error fetching revision '%s/%s' upon build completion: %v", namespace, name, err) + } + if err := c.markBuildComplete(hr, cond); err != nil { + glog.Errorf("Error marking build completion for '%s/%s': %v", namespace, name, err) + } + }(k) + } + return +} + +func (c *RevisionControllerImpl) updateBuildEvent(old, new interface{}) { + c.addBuildEvent(new) +} + +// reconcileOnceBuilt handles enqueued messages that have an image. +func (c *RevisionControllerImpl) reconcileOnceBuilt(u *v1alpha1.Revision, ns string) error { accessor, err := meta.Accessor(u) if err != nil { log.Printf("Failed to get metadata: %s", err) @@ -355,13 +555,11 @@ func (c *RevisionControllerImpl) deleteK8SResources(u *v1alpha1.Revision, ns str log.Printf("Deleted service") // And the deployment is no longer ready, so update that - u.Status.Conditions = []v1alpha1.RevisionCondition{ - { - Type: "Ready", - Status: "False", - Reason: "Inactive", - }, - } + setCondition(u, "Ready", &v1alpha1.RevisionCondition{ + Type: "Ready", + Status: "False", + Reason: "Inactive", + }) log.Printf("2. Updating status with the following conditions %+v", u.Status.Conditions) if _, err := c.updateStatus(u); err != nil { log.Printf("Error recording build completion: %s", err) @@ -401,13 +599,11 @@ func (c *RevisionControllerImpl) createK8SResources(u *v1alpha1.Revision, ns str // By updating our deployment status we will trigger a Reconcile() // that will watch for Deployment completion. - u.Status.Conditions = []v1alpha1.RevisionCondition{ - { - Type: "Ready", - Status: "False", - Reason: "Deploying", - }, - } + setCondition(u, "Ready", &v1alpha1.RevisionCondition{ + Type: "Ready", + Status: "False", + Reason: "Deploying", + }) log.Printf("2. Updating status with the following conditions %+v", u.Status.Conditions) if _, err := c.updateStatus(u); err != nil { log.Printf("Error recording build completion: %s", err) @@ -640,6 +836,19 @@ func (c *RevisionControllerImpl) removeFinalizers(u *v1alpha1.Revision, ns strin return nil } +func setCondition(u *v1alpha1.Revision, t string, new *v1alpha1.RevisionCondition) { + var conditions []v1alpha1.RevisionCondition + for _, cond := range u.Status.Conditions { + if cond.Type != t { + conditions = append(conditions, cond) + } + } + if new != nil { + conditions = append(conditions, *new) + } + u.Status.Conditions = conditions +} + func (c *RevisionControllerImpl) updateStatus(u *v1alpha1.Revision) (*v1alpha1.Revision, error) { prClient := c.elaclientset.ElafrosV1alpha1().Revisions(u.Namespace) newu, err := prClient.Get(u.Name, metav1.GetOptions{}) diff --git a/pkg/controller/revision/controller_test.go b/pkg/controller/revision/controller_test.go index 09f279db37ff..75d9db42ae7f 100644 --- a/pkg/controller/revision/controller_test.go +++ b/pkg/controller/revision/controller_test.go @@ -29,7 +29,6 @@ package revision */ import ( "fmt" - "regexp" "testing" "time" @@ -37,6 +36,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + buildv1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" "github.com/google/elafros/pkg/apis/ela/v1alpha1" fakeclientset "github.com/google/elafros/pkg/client/clientset/versioned/fake" informers "github.com/google/elafros/pkg/client/informers/externalversions" @@ -113,7 +113,7 @@ func newRunningTestController(t *testing.T) ( return } -func TestCreateHRCreatesStuff(t *testing.T) { +func TestCreateRevCreatesStuff(t *testing.T) { kubeClient, elaClient, _, _, _, stopCh := newRunningTestController(t) defer close(stopCh) rev := getTestRevision() @@ -168,39 +168,42 @@ func TestCreateHRCreatesStuff(t *testing.T) { return hooks.HookComplete }) - // Look for the nginx configmap. - expectedConfigMapName := fmt.Sprintf("%s-%s-proxy-configmap", rev.Name, rev.Spec.Service) - h.OnCreate(&kubeClient.Fake, "configmaps", func(obj runtime.Object) hooks.HookResult { - cm := obj.(*corev1.ConfigMap) - glog.Infof("checking cm %s", cm.Name) - if expectedNamespace != cm.Namespace { - t.Errorf("configmap namespace was not %s", expectedNamespace) - } - if expectedConfigMapName != cm.Name { - t.Errorf("configmap name was not %s", expectedConfigMapName) - } - //TODO assert Labels - data, ok := cm.Data["nginx.conf"] - if !ok { - t.Error("expected configmap data to have \"nginx.conf\" key") + // Ensure that the Revision status is updated. + h.OnUpdate(&elaClient.Fake, "revisions", func(obj runtime.Object) hooks.HookResult { + updatedPr := obj.(*v1alpha1.Revision) + glog.Infof("updated rev %v", updatedPr) + want := v1alpha1.RevisionCondition{ + Type: "Ready", + Status: "False", + Reason: "Deploying", } - matched, err := regexp.Match("upstream app_server.*127\\.0\\.0\\.1:8080", []byte(data)) - if err != nil { - t.Error(err) - } else if !matched { - t.Errorf("expected nginx config string to include appserver upstream with 127.0.0.1:8080, was %q", data) + if len(updatedPr.Status.Conditions) != 1 || want != updatedPr.Status.Conditions[0] { + t.Errorf("expected conditions to have 1 condition equal to %v", want) } return hooks.HookComplete }) + elaClient.ElafrosV1alpha1().Revisions("test").Create(rev) + + if err := h.WaitForHooks(time.Second * 3); err != nil { + t.Error(err) + } +} + +func TestCreateRevWithBuildNameWaits(t *testing.T) { + _, elaClient, _, _, _, stopCh := newRunningTestController(t) + defer close(stopCh) + rev := getTestRevision() + h := hooks.NewHooks() + // Ensure that the Revision status is updated. h.OnUpdate(&elaClient.Fake, "revisions", func(obj runtime.Object) hooks.HookResult { updatedPr := obj.(*v1alpha1.Revision) glog.Infof("updated rev %v", updatedPr) want := v1alpha1.RevisionCondition{ - Type: "Ready", + Type: "BuildComplete", Status: "False", - Reason: "Deploying", + Reason: "Building", } if len(updatedPr.Status.Conditions) != 1 || want != updatedPr.Status.Conditions[0] { t.Errorf("expected conditions to have 1 condition equal to %v", want) @@ -208,9 +211,255 @@ func TestCreateHRCreatesStuff(t *testing.T) { return hooks.HookComplete }) + bld := &buildv1alpha1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "foo", + }, + Spec: buildv1alpha1.BuildSpec{ + Steps: []corev1.Container{{ + Name: "nop", + Image: "busybox:latest", + Command: []string{"/bin/sh"}, + Args: []string{"-c", "echo Hello"}, + }}, + }, + } + + elaClient.CloudbuildV1alpha1().Builds("test").Create(bld) + + // Direct the Revision to wait for this build to complete. + rev.Spec.BuildName = bld.Name elaClient.ElafrosV1alpha1().Revisions("test").Create(rev) if err := h.WaitForHooks(time.Second * 3); err != nil { t.Error(err) } } + +func TestCreateRevWithFailedBuildNameFails(t *testing.T) { + _, elaClient, controller, _, _, stopCh := newRunningTestController(t) + defer close(stopCh) + rev := getTestRevision() + h := hooks.NewHooks() + + reason := "Foo" + errMessage := "a long human-readable error message." + + bld := &buildv1alpha1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "foo", + }, + Spec: buildv1alpha1.BuildSpec{ + Steps: []corev1.Container{{ + Name: "nop", + Image: "busybox:latest", + Command: []string{"/bin/sh"}, + Args: []string{"-c", "echo Hello"}, + }}, + }, + } + + // Ensure that the Revision status is updated. + update := 0 + h.OnUpdate(&elaClient.Fake, "revisions", func(obj runtime.Object) hooks.HookResult { + updatedPr := obj.(*v1alpha1.Revision) + update = update + 1 + switch update { + case 1: + // After the initial update to the revision, we should be + // watching for this build to complete, so make it complete, but + // with a failure. + bld.Status = buildv1alpha1.BuildStatus{ + Conditions: []buildv1alpha1.BuildCondition{{ + Type: buildv1alpha1.BuildFailed, + Status: corev1.ConditionTrue, + Reason: reason, + Message: errMessage, + }}, + } + + // This hangs for some reason: + // elaClient.CloudbuildV1alpha1().Builds("test").Update(bld) + // so manually trigger the build event. + controller.addBuildEvent(bld) + return hooks.HookIncomplete + + case 2: + // The next update we receive should tell us that the build failed, + // and surface the reason and message from that failure in our own + // status. + want := v1alpha1.RevisionCondition{ + Type: "BuildFailed", + Status: "True", + Reason: reason, + Message: errMessage, + } + if len(updatedPr.Status.Conditions) != 1 { + t.Errorf("want 1 condition, got %d", len(updatedPr.Status.Conditions)) + } + if want != updatedPr.Status.Conditions[0] { + t.Errorf("wanted %v, got %v", want, updatedPr.Status.Conditions[0]) + } + } + return hooks.HookComplete + }) + + // Direct the Revision to wait for this build to complete. + elaClient.CloudbuildV1alpha1().Builds("test").Create(bld) + rev.Spec.BuildName = bld.Name + elaClient.ElafrosV1alpha1().Revisions("test").Create(rev) + + if err := h.WaitForHooks(3 * time.Second); err != nil { + t.Error(err) + } +} + +func TestCreateRevWithCompletedBuildNameFails(t *testing.T) { + _, elaClient, controller, _, _, stopCh := newRunningTestController(t) + defer close(stopCh) + rev := getTestRevision() + h := hooks.NewHooks() + + bld := &buildv1alpha1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "foo", + }, + Spec: buildv1alpha1.BuildSpec{ + Steps: []corev1.Container{{ + Name: "nop", + Image: "busybox:latest", + Command: []string{"/bin/sh"}, + Args: []string{"-c", "echo Hello"}, + }}, + }, + } + + // Ensure that the Revision status is updated.\ + update := 0 + h.OnUpdate(&elaClient.Fake, "revisions", func(obj runtime.Object) hooks.HookResult { + updatedPr := obj.(*v1alpha1.Revision) + update = update + 1 + switch update { + case 1: + // After the initial update to the revision, we should be + // watching for this build to complete, so make it complete. + bld.Status = buildv1alpha1.BuildStatus{ + Conditions: []buildv1alpha1.BuildCondition{{ + Type: buildv1alpha1.BuildComplete, + Status: corev1.ConditionTrue, + }}, + } + + // This hangs for some reason: + // elaClient.CloudbuildV1alpha1().Builds("test").Update(bld) + // so manually trigger the build event. + controller.addBuildEvent(bld) + return hooks.HookIncomplete + + case 2: + // The next update we receive should tell us that the build completed. + want := v1alpha1.RevisionCondition{ + Type: "BuildComplete", + Status: "True", + } + if len(updatedPr.Status.Conditions) != 1 { + t.Errorf("want 1 condition, got %d", len(updatedPr.Status.Conditions)) + } + if want != updatedPr.Status.Conditions[0] { + t.Errorf("wanted %v, got %v", want, updatedPr.Status.Conditions[0]) + } + } + return hooks.HookComplete + }) + + // Direct the Revision to wait for this build to complete. + elaClient.CloudbuildV1alpha1().Builds("test").Create(bld) + rev.Spec.BuildName = bld.Name + elaClient.ElafrosV1alpha1().Revisions("test").Create(rev) + + if err := h.WaitForHooks(3 * time.Second); err != nil { + t.Error(err) + } +} + +func TestCreateRevWithInvalidBuildNameFails(t *testing.T) { + _, elaClient, controller, _, _, stopCh := newRunningTestController(t) + defer close(stopCh) + rev := getTestRevision() + h := hooks.NewHooks() + + reason := "Foo" + errMessage := "a long human-readable error message." + + bld := &buildv1alpha1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "foo", + }, + Spec: buildv1alpha1.BuildSpec{ + Steps: []corev1.Container{{ + Name: "nop", + Image: "busybox:latest", + Command: []string{"/bin/sh"}, + Args: []string{"-c", "echo Hello"}, + }}, + }, + } + + // Ensure that the Revision status is updated.\ + update := 0 + h.OnUpdate(&elaClient.Fake, "revisions", func(obj runtime.Object) hooks.HookResult { + updatedPr := obj.(*v1alpha1.Revision) + update = update + 1 + switch update { + case 1: + // After the initial update to the revision, we should be + // watching for this build to complete, so make it complete, but + // with a validation failure. + bld.Status = buildv1alpha1.BuildStatus{ + Conditions: []buildv1alpha1.BuildCondition{{ + Type: buildv1alpha1.BuildInvalid, + Status: corev1.ConditionTrue, + Reason: reason, + Message: errMessage, + }}, + } + + // This hangs for some reason: + // elaClient.CloudbuildV1alpha1().Builds("test").Update(bld) + // so manually trigger the build event. + controller.addBuildEvent(bld) + return hooks.HookIncomplete + + case 2: + // The next update we receive should tell us that the build failed, + // and surface the reason and message from that failure in our own + // status. + want := v1alpha1.RevisionCondition{ + Type: "BuildFailed", + Status: "True", + Reason: reason, + Message: errMessage, + } + if len(updatedPr.Status.Conditions) != 1 { + t.Errorf("want 1 condition, got %d", len(updatedPr.Status.Conditions)) + } + if want != updatedPr.Status.Conditions[0] { + t.Errorf("wanted %v, got %v", want, updatedPr.Status.Conditions[0]) + } + } + return hooks.HookComplete + }) + + // Direct the Revision to wait for this build to complete. + elaClient.CloudbuildV1alpha1().Builds("test").Create(bld) + rev.Spec.BuildName = bld.Name + elaClient.ElafrosV1alpha1().Revisions("test").Create(rev) + + if err := h.WaitForHooks(3 * time.Second); err != nil { + t.Error(err) + } +} diff --git a/pkg/controller/revisiontemplate/BUILD.bazel b/pkg/controller/revisiontemplate/BUILD.bazel index 96f9adfd9cc4..0adfa56079ce 100644 --- a/pkg/controller/revisiontemplate/BUILD.bazel +++ b/pkg/controller/revisiontemplate/BUILD.bazel @@ -6,6 +6,7 @@ go_library( importpath = "github.com/google/elafros/pkg/controller/revisiontemplate", visibility = ["//visibility:public"], deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/client/clientset/versioned:go_default_library", "//pkg/client/clientset/versioned/scheme:go_default_library", @@ -36,11 +37,13 @@ go_test( embed = [":go_default_library"], importpath = "github.com/google/elafros/pkg/controller/revisiontemplate", deps = [ + "//pkg/apis/cloudbuild/v1alpha1:go_default_library", "//pkg/apis/ela/v1alpha1:go_default_library", "//pkg/client/clientset/versioned/fake:go_default_library", "//pkg/client/informers/externalversions:go_default_library", "//pkg/controller/testing:go_default_library", "//vendor/github.com/golang/glog:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/client-go/informers:go_default_library", diff --git a/pkg/controller/revisiontemplate/controller.go b/pkg/controller/revisiontemplate/controller.go index 755c36f66352..1e7c9a0ffc93 100644 --- a/pkg/controller/revisiontemplate/controller.go +++ b/pkg/controller/revisiontemplate/controller.go @@ -39,6 +39,7 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" + buildv1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" "github.com/google/elafros/pkg/apis/ela/v1alpha1" clientset "github.com/google/elafros/pkg/client/clientset/versioned" elascheme "github.com/google/elafros/pkg/client/clientset/versioned/scheme" @@ -48,6 +49,8 @@ import ( const controllerAgentName = "revisiontemplate-controller" +var controllerKind = v1alpha1.SchemeGroupVersion.WithKind("RevisionTemplate") + const ( // SuccessSynced is used as part of the Event 'reason' when a Foo is synced SuccessSynced = "Synced" @@ -63,8 +66,8 @@ const ( // Controller implements the controller for RevisionTemplate resources type Controller struct { // kubeclientset is a standard kubernetes clientset - kubeclientset kubernetes.Interface - elaclientset clientset.Interface + kubeclientset kubernetes.Interface + elaclientset clientset.Interface // lister indexes properties about RevisionTemplate lister listers.RevisionTemplateLister @@ -105,12 +108,12 @@ func NewController( recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: controllerAgentName}) controller := &Controller{ - kubeclientset: kubeclientset, - elaclientset: elaclientset, - lister: informer.Lister(), - synced: informer.Informer().HasSynced, - workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "RevisionTemplates"), - recorder: recorder, + kubeclientset: kubeclientset, + elaclientset: elaclientset, + lister: informer.Lister(), + synced: informer.Informer().HasSynced, + workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "RevisionTemplates"), + recorder: recorder, } glog.Info("Setting up event handlers") @@ -258,6 +261,8 @@ func (c *Controller) syncHandler(key string) error { return err } + // Don't modify the informer's copy. + rt = rt.DeepCopy() // RevisionTemplate business logic // TODO: Once this bug gets fixed, use rt.Generation instead @@ -269,13 +274,35 @@ func (c *Controller) syncHandler(key string) error { } glog.Infof("Running reconcile RevisionTemplate for %s\n%+v\n%+v\n", rt.Name, rt, rt.Spec.Template) - revName, err := generateRevisionName(rt) - if err != nil { - return err + spec := rt.Spec.Template.Spec + + if rt.Spec.Build != nil { + // TODO(mattmoor): Determine whether we reuse the previous build. + build := &buildv1alpha1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: rt.Namespace, + GenerateName: fmt.Sprintf("%s-", rt.Name), + }, + Spec: *rt.Spec.Build, + } + controllerRef := metav1.NewControllerRef(rt, controllerKind) + build.OwnerReferences = append(build.OwnerReferences, *controllerRef) + created, err := c.elaclientset.CloudbuildV1alpha1().Builds(build.Namespace).Create(build) + if err != nil { + glog.Errorf("Failed to create Build:\n%+v\n%s", build, err) + return err + } + glog.Infof("Created Build:\n%+v", created.Name) + spec.BuildName = created.Name } + rev := &v1alpha1.Revision{ ObjectMeta: rt.Spec.Template.ObjectMeta, - Spec: rt.Spec.Template.Spec, + Spec: spec, + } + revName, err := generateRevisionName(rt) + if err != nil { + return err } // TODO: Should this just use rev.ObjectMeta.GenerateName = rev.ObjectMeta.Name = revName diff --git a/pkg/controller/revisiontemplate/controller_test.go b/pkg/controller/revisiontemplate/controller_test.go index 7123ffbef39b..41bda17e4fda 100644 --- a/pkg/controller/revisiontemplate/controller_test.go +++ b/pkg/controller/revisiontemplate/controller_test.go @@ -31,9 +31,11 @@ import ( "time" "github.com/golang/glog" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + buildv1alpha1 "github.com/google/elafros/pkg/apis/cloudbuild/v1alpha1" "github.com/google/elafros/pkg/apis/ela/v1alpha1" fakeclientset "github.com/google/elafros/pkg/client/clientset/versioned/fake" informers "github.com/google/elafros/pkg/client/informers/externalversions" @@ -132,3 +134,48 @@ func TestCreateRTCreatesPR(t *testing.T) { t.Error(err) } } + +func TestCreateRTCreatesBuildAndPR(t *testing.T) { + _, elaClient, _, _, _, stopCh := newRunningTestController(t) + defer close(stopCh) + rt := getTestRevisionTemplate() + h := hooks.NewHooks() + + rt.Spec.Build = &buildv1alpha1.BuildSpec{ + Steps: []corev1.Container{{ + Name: "nop", + Image: "busybox:latest", + Command: []string{"/bin/sh"}, + Args: []string{"-c", "echo Hello"}, + }}, + } + + h.OnCreate(&elaClient.Fake, "builds", func(obj runtime.Object) hooks.HookResult { + b := obj.(*buildv1alpha1.Build) + glog.Infof("checking build %s", b.Name) + if rt.Spec.Build.Steps[0].Name != b.Spec.Steps[0].Name { + t.Errorf("BuildSpec mismatch; want %v, got %v", rt.Spec.Build.Steps[0], b.Spec.Steps[0]) + } + return hooks.HookComplete + }) + + h.OnCreate(&elaClient.Fake, "revisions", func(obj runtime.Object) hooks.HookResult { + hr := obj.(*v1alpha1.Revision) + glog.Infof("checking revision %s", hr.Name) + if rt.Spec.Template.Spec.Service != hr.Spec.Service { + t.Errorf("hr service was not %s", rt.Spec.Template.Spec.Service) + } + // TODO(mattmoor): The fake doesn't properly support GenerateName, + // so it never looks like the BuildName is populated. + // if hr.Spec.BuildName == "" { + // t.Error("Missing BuildName; want non-empty, but got empty string") + // } + return hooks.HookComplete + }) + + elaClient.ElafrosV1alpha1().RevisionTemplates("test").Create(rt) + + if err := h.WaitForHooks(time.Second * 3); err != nil { + t.Error(err) + } +} diff --git a/pkg/controller/testing/hooks_test.go b/pkg/controller/testing/hooks_test.go index f0126b877312..bf7ade1891b8 100644 --- a/pkg/controller/testing/hooks_test.go +++ b/pkg/controller/testing/hooks_test.go @@ -27,7 +27,7 @@ import ( "k8s.io/client-go/kubernetes/fake" ) -func Example_hooks() { +func TestHooks(t *testing.T) { h := NewHooks() f := fake.NewSimpleClientset() @@ -63,7 +63,9 @@ func Example_hooks() { f.CoreV1().Pods("test").Update(updatedPod) f.CoreV1().Pods("test").Delete(pod.Name, &metav1.DeleteOptions{}) - h.WaitForHooks(time.Second) + if err := h.WaitForHooks(time.Second); err != nil { + t.Error(err) + } // Output: // Pod test-pod has restart policy Always @@ -124,3 +126,46 @@ func TestWaitPartialCompletion(t *testing.T) { t.Error("expected create hook to be called") } } + +func TestMultiUpdate(t *testing.T) { + h := NewHooks() + f := fake.NewSimpleClientset() + + updates := 0 + h.OnUpdate(&f.Fake, "pods", func(obj runtime.Object) HookResult { + updates = updates + 1 + switch updates { + case 1: + case 2: + return HookComplete + } + return HookIncomplete + }) + + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + }, + Spec: v1.PodSpec{ + RestartPolicy: v1.RestartPolicyAlways, + }, + } + f.CoreV1().Pods("test").Create(pod) + + updatedPod := pod.DeepCopy() + updatedPod.Spec.RestartPolicy = v1.RestartPolicyNever + f.CoreV1().Pods("test").Update(updatedPod) + + updatedPod = pod.DeepCopy() + updatedPod.Spec.RestartPolicy = v1.RestartPolicyAlways + f.CoreV1().Pods("test").Update(updatedPod) + + f.CoreV1().Pods("test").Delete(pod.Name, &metav1.DeleteOptions{}) + if err := h.WaitForHooks(time.Second); err != nil { + t.Error(err) + } + + if updates != 2 { + t.Errorf("Unexpected number of Update events; want 2, got %d", updates) + } +} diff --git a/sample/revisiontemplate.yaml b/sample/revisiontemplate.yaml index e754df987f42..b258a46f7754 100644 --- a/sample/revisiontemplate.yaml +++ b/sample/revisiontemplate.yaml @@ -18,6 +18,13 @@ metadata: name: revisiontemplate-example namespace: default spec: + # Inline a trivial non-build for now (we build the image with Bazel). + build: + steps: + - name: blah + image: busybox:latest + args: ["echo", "Hello"] + template: spec: serviceType: container