diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..ddadb3976 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +vendor/* linguist-vendored +pkg/client/* linguist-generated +zz_generated* linguist-generated diff --git a/Gopkg.lock b/Gopkg.lock index 24f55890b..42c45797b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -150,6 +150,14 @@ revision = "b9bbc5664f49b6deec52393bd68f39830687a347" version = "v2.9.3" +[[projects]] + digest = "1:4322fcb2f4d508898c3d9b0390a2e58211b53e6d9c25230b225df9a032fe26d6" + name = "github.com/evanphx/json-patch" + packages = ["."] + pruneopts = "NT" + revision = "5858425f75500d40c52783dce87d085a483ce135" + version = "v4.2.0" + [[projects]] digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756" name = "github.com/ghodss/yaml" @@ -1120,6 +1128,7 @@ packages = [ "discovery", "discovery/cached", + "discovery/fake", "dynamic", "kubernetes", "kubernetes/scheme", @@ -1168,6 +1177,7 @@ "rest", "rest/watch", "restmapper", + "testing", "third_party/forked/golang/template", "tools/auth", "tools/cache", @@ -1380,9 +1390,9 @@ "github.com/operator-framework/operator-sdk/pkg/test/e2eutil", "github.com/operator-framework/operator-sdk/version", "github.com/oracle/mysql-operator/pkg/apis/mysql/v1alpha1", + "github.com/pborman/uuid", "github.com/pkg/errors", "github.com/sirupsen/logrus", - "github.com/pborman/uuid", "github.com/spf13/pflag", "github.com/stretchr/testify/assert", "golang.org/x/net/context", @@ -1393,13 +1403,22 @@ "k8s.io/apimachinery/pkg/api/errors", "k8s.io/apimachinery/pkg/api/resource", "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/labels", "k8s.io/apimachinery/pkg/runtime", "k8s.io/apimachinery/pkg/runtime/schema", + "k8s.io/apimachinery/pkg/runtime/serializer", "k8s.io/apimachinery/pkg/types", "k8s.io/apimachinery/pkg/util/intstr", + "k8s.io/apimachinery/pkg/util/runtime", + "k8s.io/apimachinery/pkg/watch", + "k8s.io/client-go/discovery", + "k8s.io/client-go/discovery/fake", "k8s.io/client-go/kubernetes/scheme", "k8s.io/client-go/plugin/pkg/client/auth/gcp", "k8s.io/client-go/rest", + "k8s.io/client-go/testing", + "k8s.io/client-go/tools/cache", + "k8s.io/client-go/util/flowcontrol", "k8s.io/code-generator/cmd/client-gen", "k8s.io/code-generator/cmd/conversion-gen", "k8s.io/code-generator/cmd/deepcopy-gen", diff --git a/Makefile b/Makefile index 53b1b8675..9e74abb7c 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ govet: ## Runs govet against all packages. generate: ## Runs the kubernetes code-generators and openapi operator-sdk generate k8s operator-sdk generate openapi + vendor/k8s.io/code-generator/generate-groups.sh all github.com/mattermost/mattermost-operator/pkg/client github.com/mattermost/mattermost-operator/pkg/apis mattermost:v1alpha1 dep: ## Get dependencies diff --git a/README.md b/README.md index be4a19a53..6835b26ab 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The Mattermost operator is in alpha, data loss might occur. ## Summary -Mattermost is a scalale, open source collaboration tool. It's written in Golang and React. +Mattermost is a scalable, open source collaboration tool. It's written in Golang and React. This project offers a Kubernetes Operator for Mattermost to simplify deploying and managing your Mattermost instance. diff --git a/build/Dockerfile b/build/Dockerfile index c32ed26b5..59d9c6aed 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -6,7 +6,6 @@ FROM ${BUILD_IMAGE} AS build WORKDIR /go/src/github.com/mattermost/mattermost-operator/ COPY . /go/src/github.com/mattermost/mattermost-operator/ RUN cp build/operator-sdk /usr/local/bin/ -RUN make generate RUN make build # Final Image diff --git a/deploy/crds/mattermost_v1alpha1_clusterinstallation_crd.yaml b/deploy/crds/mattermost_v1alpha1_clusterinstallation_crd.yaml index 3f6bb6d89..50cfee014 100644 --- a/deploy/crds/mattermost_v1alpha1_clusterinstallation_crd.yaml +++ b/deploy/crds/mattermost_v1alpha1_clusterinstallation_crd.yaml @@ -80,18 +80,17 @@ spec: Not included when requesting from the apiserver, only from the Mattermost Operator API itself. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status' properties: - paused: - description: Represents whether any actions on the underlying managed - objects are being performed. Only delete actions will be performed. - type: boolean replicas: description: Total number of non-terminated pods targeted by this Mattermost deployment (their labels match the selector). format: int32 type: integer - required: - - paused - - replicas + state: + description: Represents the running state of the Mattermost instance + type: string + version: + description: The version currently running in the Mattermost instance + type: string type: object required: - spec diff --git a/pkg/apis/mattermost/v1alpha1/clusterinstallation_types.go b/pkg/apis/mattermost/v1alpha1/clusterinstallation_types.go index 54691e755..e329608e5 100644 --- a/pkg/apis/mattermost/v1alpha1/clusterinstallation_types.go +++ b/pkg/apis/mattermost/v1alpha1/clusterinstallation_types.go @@ -5,6 +5,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +//////////////////////////////////////////////////////////////////////////////// +// IMPORTANT! // +//////////////////////////////////////////////////////////////////////////////// +// Run "make generate" in the root of this repository to regenerate code // +// after modifying this file. // +// Add custom validation using kubebuilder tags: // +// https://book.kubebuilder.io/beyond_basics/generating_crd.html // +//////////////////////////////////////////////////////////////////////////////// + // ClusterInstallationSpec defines the desired state of ClusterInstallation // +k8s:openapi-gen=true type ClusterInstallationSpec struct { @@ -39,20 +48,33 @@ type DatabaseType struct { ExternalDatabaseSecret string `json:"externalDatabaseSecret,omitempty"` } +// RunningState is the state of the Mattermost instance +type RunningState string + +const ( + // Creating is the state when the Mattermost instance is being created + Creating RunningState = "creating" + // Upgrading is the state when the Mattermost instance is being upgraded + Upgrading RunningState = "upgrading" + // Running is the state when the Mattermost instance is fully running + Running RunningState = "running" +) + // ClusterInstallationStatus defines the observed state of ClusterInstallation -// +k8s:openapi-gen=true type ClusterInstallationStatus struct { - // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file - // Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html - - // Represents whether any actions on the underlying managed objects are - // being performed. Only delete actions will be performed. - Paused bool `json:"paused"` + // Represents the running state of the Mattermost instance + // +optional + State RunningState `json:"state,omitempty"` // Total number of non-terminated pods targeted by this Mattermost deployment // (their labels match the selector). - Replicas int32 `json:"replicas"` + // +optional + Replicas int32 `json:"replicas,omitempty"` + // The version currently running in the Mattermost instance + // +optional + Version string `json:"version,omitempty"` } +// +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // ClusterInstallation is the Schema for the clusterinstallations API @@ -70,7 +92,7 @@ type ClusterInstallation struct { // included when requesting from the apiserver, only from the Mattermost // Operator API itself. More info: // https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status - Status *ClusterInstallationStatus `json:"status,omitempty"` + Status ClusterInstallationStatus `json:"status,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -81,7 +103,3 @@ type ClusterInstallationList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []ClusterInstallation `json:"items"` } - -func init() { - SchemeBuilder.Register(&ClusterInstallation{}, &ClusterInstallationList{}) -} diff --git a/pkg/apis/mattermost/v1alpha1/clusterinstallation_utils.go b/pkg/apis/mattermost/v1alpha1/clusterinstallation_utils.go index 9504bf829..0f0ae7459 100644 --- a/pkg/apis/mattermost/v1alpha1/clusterinstallation_utils.go +++ b/pkg/apis/mattermost/v1alpha1/clusterinstallation_utils.go @@ -1,6 +1,7 @@ package v1alpha1 import ( + "errors" "fmt" appsv1 "k8s.io/api/apps/v1" @@ -33,28 +34,24 @@ const ( // SetDefaults set the missing values in the manifest to the default ones func (mattermost *ClusterInstallation) SetDefaults() error { if mattermost.Spec.IngressName == "" { - return fmt.Errorf("need to set the IngressName") + return errors.New("IngressName required, but not set") } - if mattermost.Spec.Image == "" { mattermost.Spec.Image = DefaultMattermostImage } - if mattermost.Spec.Version == "" { mattermost.Spec.Version = DefaultMattermostVersion } - if mattermost.Spec.Replicas == 0 { mattermost.Spec.Replicas = DefaultAmountOfPods } - if mattermost.Spec.MinioStorageSize == "" { mattermost.Spec.MinioStorageSize = DefaultMinioStorageSize } - if len(mattermost.Spec.DatabaseType.Type) == 0 { mattermost.Spec.DatabaseType.Type = DefaultMattermostDatabaseType } + return nil } diff --git a/pkg/apis/mattermost/v1alpha1/register.go b/pkg/apis/mattermost/v1alpha1/register.go index 02179ccfa..6cfddfdea 100644 --- a/pkg/apis/mattermost/v1alpha1/register.go +++ b/pkg/apis/mattermost/v1alpha1/register.go @@ -6,14 +6,37 @@ package v1alpha1 import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" ) -var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: "mattermost.com", Version: "v1alpha1"} +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: "mattermost.com", 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() +} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +var ( + //SchemeBuilder is the builder object for the mattermost scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + //AddToScheme is the function to add a mattermost scheme to the serializer. + AddToScheme = SchemeBuilder.AddToScheme ) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &ClusterInstallation{}, + &ClusterInstallationList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/mattermost/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/mattermost/v1alpha1/zz_generated.deepcopy.go index 8da42d93c..b8d384fa5 100644 --- a/pkg/apis/mattermost/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/mattermost/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,21 @@ // +build !ignore_autogenerated +/* +Copyright 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. +*/ + // Code generated by deepcopy-gen. DO NOT EDIT. package v1alpha1 @@ -15,11 +31,7 @@ func (in *ClusterInstallation) DeepCopyInto(out *ClusterInstallation) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - if in.Status != nil { - in, out := &in.Status, &out.Status - *out = new(ClusterInstallationStatus) - **out = **in - } + out.Status = in.Status return } diff --git a/pkg/apis/mattermost/v1alpha1/zz_generated.openapi.go b/pkg/apis/mattermost/v1alpha1/zz_generated.openapi.go index decb10102..e1dc37b98 100644 --- a/pkg/apis/mattermost/v1alpha1/zz_generated.openapi.go +++ b/pkg/apis/mattermost/v1alpha1/zz_generated.openapi.go @@ -13,9 +13,8 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1.ClusterInstallation": schema_pkg_apis_mattermost_v1alpha1_ClusterInstallation(ref), - "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1.ClusterInstallationSpec": schema_pkg_apis_mattermost_v1alpha1_ClusterInstallationSpec(ref), - "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1.ClusterInstallationStatus": schema_pkg_apis_mattermost_v1alpha1_ClusterInstallationStatus(ref), + "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1.ClusterInstallation": schema_pkg_apis_mattermost_v1alpha1_ClusterInstallation(ref), + "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1.ClusterInstallationSpec": schema_pkg_apis_mattermost_v1alpha1_ClusterInstallationSpec(ref), } } @@ -134,31 +133,3 @@ func schema_pkg_apis_mattermost_v1alpha1_ClusterInstallationSpec(ref common.Refe "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1.DatabaseType", "k8s.io/api/core/v1.Affinity"}, } } - -func schema_pkg_apis_mattermost_v1alpha1_ClusterInstallationStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "ClusterInstallationStatus defines the observed state of ClusterInstallation", - Properties: map[string]spec.Schema{ - "paused": { - SchemaProps: spec.SchemaProps{ - Description: "Represents whether any actions on the underlying managed objects are being performed. Only delete actions will be performed.", - Type: []string{"boolean"}, - Format: "", - }, - }, - "replicas": { - SchemaProps: spec.SchemaProps{ - Description: "Total number of non-terminated pods targeted by this Mattermost deployment (their labels match the selector).", - Type: []string{"integer"}, - Format: "int32", - }, - }, - }, - Required: []string{"paused", "replicas"}, - }, - }, - Dependencies: []string{}, - } -} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go new file mode 100644 index 000000000..a7f12e903 --- /dev/null +++ b/pkg/client/clientset/versioned/clientset.go @@ -0,0 +1,98 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + mattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned/typed/mattermost/v1alpha1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + MattermostV1alpha1() mattermostv1alpha1.MattermostV1alpha1Interface + // Deprecated: please explicitly pick a version if possible. + Mattermost() mattermostv1alpha1.MattermostV1alpha1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + mattermostV1alpha1 *mattermostv1alpha1.MattermostV1alpha1Client +} + +// MattermostV1alpha1 retrieves the MattermostV1alpha1Client +func (c *Clientset) MattermostV1alpha1() mattermostv1alpha1.MattermostV1alpha1Interface { + return c.mattermostV1alpha1 +} + +// Deprecated: Mattermost retrieves the default version of MattermostClient. +// Please explicitly pick a version. +func (c *Clientset) Mattermost() mattermostv1alpha1.MattermostV1alpha1Interface { + return c.mattermostV1alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.mattermostV1alpha1, err = mattermostv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.mattermostV1alpha1 = mattermostv1alpha1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.mattermostV1alpha1 = mattermostv1alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/client/clientset/versioned/doc.go b/pkg/client/clientset/versioned/doc.go new file mode 100644 index 000000000..41721ca52 --- /dev/null +++ b/pkg/client/clientset/versioned/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..855b46c3f --- /dev/null +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,82 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + clientset "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned" + mattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned/typed/mattermost/v1alpha1" + fakemattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// MattermostV1alpha1 retrieves the MattermostV1alpha1Client +func (c *Clientset) MattermostV1alpha1() mattermostv1alpha1.MattermostV1alpha1Interface { + return &fakemattermostv1alpha1.FakeMattermostV1alpha1{Fake: &c.Fake} +} + +// Mattermost retrieves the MattermostV1alpha1Client +func (c *Clientset) Mattermost() mattermostv1alpha1.MattermostV1alpha1Interface { + return &fakemattermostv1alpha1.FakeMattermostV1alpha1{Fake: &c.Fake} +} diff --git a/pkg/client/clientset/versioned/fake/doc.go b/pkg/client/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/pkg/client/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go new file mode 100644 index 000000000..9adf66d27 --- /dev/null +++ b/pkg/client/clientset/versioned/fake/register.go @@ -0,0 +1,56 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + mattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + mattermostv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/pkg/client/clientset/versioned/scheme/doc.go b/pkg/client/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..7dc375616 --- /dev/null +++ b/pkg/client/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..7bfa644f5 --- /dev/null +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -0,0 +1,56 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + mattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + mattermostv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/clusterinstallation.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/clusterinstallation.go new file mode 100644 index 000000000..dd88de081 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/clusterinstallation.go @@ -0,0 +1,191 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "time" + + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + scheme "github.com/mattermost/mattermost-operator/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" +) + +// ClusterInstallationsGetter has a method to return a ClusterInstallationInterface. +// A group's client should implement this interface. +type ClusterInstallationsGetter interface { + ClusterInstallations(namespace string) ClusterInstallationInterface +} + +// ClusterInstallationInterface has methods to work with ClusterInstallation resources. +type ClusterInstallationInterface interface { + Create(*v1alpha1.ClusterInstallation) (*v1alpha1.ClusterInstallation, error) + Update(*v1alpha1.ClusterInstallation) (*v1alpha1.ClusterInstallation, error) + UpdateStatus(*v1alpha1.ClusterInstallation) (*v1alpha1.ClusterInstallation, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.ClusterInstallation, error) + List(opts v1.ListOptions) (*v1alpha1.ClusterInstallationList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ClusterInstallation, err error) + ClusterInstallationExpansion +} + +// clusterInstallations implements ClusterInstallationInterface +type clusterInstallations struct { + client rest.Interface + ns string +} + +// newClusterInstallations returns a ClusterInstallations +func newClusterInstallations(c *MattermostV1alpha1Client, namespace string) *clusterInstallations { + return &clusterInstallations{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the clusterInstallation, and returns the corresponding clusterInstallation object, and an error if there is any. +func (c *clusterInstallations) Get(name string, options v1.GetOptions) (result *v1alpha1.ClusterInstallation, err error) { + result = &v1alpha1.ClusterInstallation{} + err = c.client.Get(). + Namespace(c.ns). + Resource("clusterinstallations"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ClusterInstallations that match those selectors. +func (c *clusterInstallations) List(opts v1.ListOptions) (result *v1alpha1.ClusterInstallationList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ClusterInstallationList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("clusterinstallations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested clusterInstallations. +func (c *clusterInstallations) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("clusterinstallations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a clusterInstallation and creates it. Returns the server's representation of the clusterInstallation, and an error, if there is any. +func (c *clusterInstallations) Create(clusterInstallation *v1alpha1.ClusterInstallation) (result *v1alpha1.ClusterInstallation, err error) { + result = &v1alpha1.ClusterInstallation{} + err = c.client.Post(). + Namespace(c.ns). + Resource("clusterinstallations"). + Body(clusterInstallation). + Do(). + Into(result) + return +} + +// Update takes the representation of a clusterInstallation and updates it. Returns the server's representation of the clusterInstallation, and an error, if there is any. +func (c *clusterInstallations) Update(clusterInstallation *v1alpha1.ClusterInstallation) (result *v1alpha1.ClusterInstallation, err error) { + result = &v1alpha1.ClusterInstallation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("clusterinstallations"). + Name(clusterInstallation.Name). + Body(clusterInstallation). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *clusterInstallations) UpdateStatus(clusterInstallation *v1alpha1.ClusterInstallation) (result *v1alpha1.ClusterInstallation, err error) { + result = &v1alpha1.ClusterInstallation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("clusterinstallations"). + Name(clusterInstallation.Name). + SubResource("status"). + Body(clusterInstallation). + Do(). + Into(result) + return +} + +// Delete takes name of the clusterInstallation and deletes it. Returns an error if one occurs. +func (c *clusterInstallations) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("clusterinstallations"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *clusterInstallations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("clusterinstallations"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched clusterInstallation. +func (c *clusterInstallations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ClusterInstallation, err error) { + result = &v1alpha1.ClusterInstallation{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("clusterinstallations"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/doc.go new file mode 100644 index 000000000..df51baa4d --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/fake_clusterinstallation.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/fake_clusterinstallation.go new file mode 100644 index 000000000..47357fce6 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/fake_clusterinstallation.go @@ -0,0 +1,140 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/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" +) + +// FakeClusterInstallations implements ClusterInstallationInterface +type FakeClusterInstallations struct { + Fake *FakeMattermostV1alpha1 + ns string +} + +var clusterinstallationsResource = schema.GroupVersionResource{Group: "mattermost.com", Version: "v1alpha1", Resource: "clusterinstallations"} + +var clusterinstallationsKind = schema.GroupVersionKind{Group: "mattermost.com", Version: "v1alpha1", Kind: "ClusterInstallation"} + +// Get takes name of the clusterInstallation, and returns the corresponding clusterInstallation object, and an error if there is any. +func (c *FakeClusterInstallations) Get(name string, options v1.GetOptions) (result *v1alpha1.ClusterInstallation, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(clusterinstallationsResource, c.ns, name), &v1alpha1.ClusterInstallation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInstallation), err +} + +// List takes label and field selectors, and returns the list of ClusterInstallations that match those selectors. +func (c *FakeClusterInstallations) List(opts v1.ListOptions) (result *v1alpha1.ClusterInstallationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(clusterinstallationsResource, clusterinstallationsKind, c.ns, opts), &v1alpha1.ClusterInstallationList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ClusterInstallationList{ListMeta: obj.(*v1alpha1.ClusterInstallationList).ListMeta} + for _, item := range obj.(*v1alpha1.ClusterInstallationList).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 clusterInstallations. +func (c *FakeClusterInstallations) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(clusterinstallationsResource, c.ns, opts)) + +} + +// Create takes the representation of a clusterInstallation and creates it. Returns the server's representation of the clusterInstallation, and an error, if there is any. +func (c *FakeClusterInstallations) Create(clusterInstallation *v1alpha1.ClusterInstallation) (result *v1alpha1.ClusterInstallation, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(clusterinstallationsResource, c.ns, clusterInstallation), &v1alpha1.ClusterInstallation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInstallation), err +} + +// Update takes the representation of a clusterInstallation and updates it. Returns the server's representation of the clusterInstallation, and an error, if there is any. +func (c *FakeClusterInstallations) Update(clusterInstallation *v1alpha1.ClusterInstallation) (result *v1alpha1.ClusterInstallation, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(clusterinstallationsResource, c.ns, clusterInstallation), &v1alpha1.ClusterInstallation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInstallation), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterInstallations) UpdateStatus(clusterInstallation *v1alpha1.ClusterInstallation) (*v1alpha1.ClusterInstallation, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(clusterinstallationsResource, "status", c.ns, clusterInstallation), &v1alpha1.ClusterInstallation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInstallation), err +} + +// Delete takes name of the clusterInstallation and deletes it. Returns an error if one occurs. +func (c *FakeClusterInstallations) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(clusterinstallationsResource, c.ns, name), &v1alpha1.ClusterInstallation{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterInstallations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(clusterinstallationsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.ClusterInstallationList{}) + return err +} + +// Patch applies the patch and returns the patched clusterInstallation. +func (c *FakeClusterInstallations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ClusterInstallation, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(clusterinstallationsResource, c.ns, name, pt, data, subresources...), &v1alpha1.ClusterInstallation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ClusterInstallation), err +} diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/fake_mattermost_client.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/fake_mattermost_client.go new file mode 100644 index 000000000..056270853 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/fake/fake_mattermost_client.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned/typed/mattermost/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeMattermostV1alpha1 struct { + *testing.Fake +} + +func (c *FakeMattermostV1alpha1) ClusterInstallations(namespace string) v1alpha1.ClusterInstallationInterface { + return &FakeClusterInstallations{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeMattermostV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/generated_expansion.go new file mode 100644 index 000000000..57973c2e7 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type ClusterInstallationExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/mattermost_client.go b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/mattermost_client.go new file mode 100644 index 000000000..46eb7e058 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/mattermost/v1alpha1/mattermost_client.go @@ -0,0 +1,90 @@ +/* +Copyright 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type MattermostV1alpha1Interface interface { + RESTClient() rest.Interface + ClusterInstallationsGetter +} + +// MattermostV1alpha1Client is used to interact with features provided by the mattermost.com group. +type MattermostV1alpha1Client struct { + restClient rest.Interface +} + +func (c *MattermostV1alpha1Client) ClusterInstallations(namespace string) ClusterInstallationInterface { + return newClusterInstallations(c, namespace) +} + +// NewForConfig creates a new MattermostV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*MattermostV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &MattermostV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new MattermostV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *MattermostV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new MattermostV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *MattermostV1alpha1Client { + return &MattermostV1alpha1Client{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 *MattermostV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go new file mode 100644 index 000000000..99646fcff --- /dev/null +++ b/pkg/client/informers/externalversions/factory.go @@ -0,0 +1,180 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/mattermost/mattermost-operator/pkg/client/informers/externalversions/internalinterfaces" + mattermost "github.com/mattermost/mattermost-operator/pkg/client/informers/externalversions/mattermost" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Mattermost() mattermost.Interface +} + +func (f *sharedInformerFactory) Mattermost() mattermost.Interface { + return mattermost.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go new file mode 100644 index 000000000..a6a02a41f --- /dev/null +++ b/pkg/client/informers/externalversions/generic.go @@ -0,0 +1,62 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=mattermost.com, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("clusterinstallations"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Mattermost().V1alpha1().ClusterInstallations().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..14c76f797 --- /dev/null +++ b/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/pkg/client/informers/externalversions/mattermost/interface.go b/pkg/client/informers/externalversions/mattermost/interface.go new file mode 100644 index 000000000..7aab93c9a --- /dev/null +++ b/pkg/client/informers/externalversions/mattermost/interface.go @@ -0,0 +1,46 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package mattermost + +import ( + internalinterfaces "github.com/mattermost/mattermost-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/client/informers/externalversions/mattermost/v1alpha1" +) + +// 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/mattermost/v1alpha1/clusterinstallation.go b/pkg/client/informers/externalversions/mattermost/v1alpha1/clusterinstallation.go new file mode 100644 index 000000000..38a9ffaba --- /dev/null +++ b/pkg/client/informers/externalversions/mattermost/v1alpha1/clusterinstallation.go @@ -0,0 +1,89 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + mattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + versioned "github.com/mattermost/mattermost-operator/pkg/client/clientset/versioned" + internalinterfaces "github.com/mattermost/mattermost-operator/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/client/listers/mattermost/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" +) + +// ClusterInstallationInformer provides access to a shared informer and lister for +// ClusterInstallations. +type ClusterInstallationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ClusterInstallationLister +} + +type clusterInstallationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewClusterInstallationInformer constructs a new informer for ClusterInstallation 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 NewClusterInstallationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterInstallationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterInstallationInformer constructs a new informer for ClusterInstallation 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 NewFilteredClusterInstallationInformer(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.MattermostV1alpha1().ClusterInstallations(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.MattermostV1alpha1().ClusterInstallations(namespace).Watch(options) + }, + }, + &mattermostv1alpha1.ClusterInstallation{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterInstallationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterInstallationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterInstallationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&mattermostv1alpha1.ClusterInstallation{}, f.defaultInformer) +} + +func (f *clusterInstallationInformer) Lister() v1alpha1.ClusterInstallationLister { + return v1alpha1.NewClusterInstallationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/mattermost/v1alpha1/interface.go b/pkg/client/informers/externalversions/mattermost/v1alpha1/interface.go new file mode 100644 index 000000000..cff43a16f --- /dev/null +++ b/pkg/client/informers/externalversions/mattermost/v1alpha1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "github.com/mattermost/mattermost-operator/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterInstallations returns a ClusterInstallationInformer. + ClusterInstallations() ClusterInstallationInformer +} + +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} +} + +// ClusterInstallations returns a ClusterInstallationInformer. +func (v *version) ClusterInstallations() ClusterInstallationInformer { + return &clusterInstallationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/listers/mattermost/v1alpha1/clusterinstallation.go b/pkg/client/listers/mattermost/v1alpha1/clusterinstallation.go new file mode 100644 index 000000000..3155ad380 --- /dev/null +++ b/pkg/client/listers/mattermost/v1alpha1/clusterinstallation.go @@ -0,0 +1,94 @@ +/* +Copyright 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ClusterInstallationLister helps list ClusterInstallations. +type ClusterInstallationLister interface { + // List lists all ClusterInstallations in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.ClusterInstallation, err error) + // ClusterInstallations returns an object that can list and get ClusterInstallations. + ClusterInstallations(namespace string) ClusterInstallationNamespaceLister + ClusterInstallationListerExpansion +} + +// clusterInstallationLister implements the ClusterInstallationLister interface. +type clusterInstallationLister struct { + indexer cache.Indexer +} + +// NewClusterInstallationLister returns a new ClusterInstallationLister. +func NewClusterInstallationLister(indexer cache.Indexer) ClusterInstallationLister { + return &clusterInstallationLister{indexer: indexer} +} + +// List lists all ClusterInstallations in the indexer. +func (s *clusterInstallationLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterInstallation, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ClusterInstallation)) + }) + return ret, err +} + +// ClusterInstallations returns an object that can list and get ClusterInstallations. +func (s *clusterInstallationLister) ClusterInstallations(namespace string) ClusterInstallationNamespaceLister { + return clusterInstallationNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ClusterInstallationNamespaceLister helps list and get ClusterInstallations. +type ClusterInstallationNamespaceLister interface { + // List lists all ClusterInstallations in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.ClusterInstallation, err error) + // Get retrieves the ClusterInstallation from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.ClusterInstallation, error) + ClusterInstallationNamespaceListerExpansion +} + +// clusterInstallationNamespaceLister implements the ClusterInstallationNamespaceLister +// interface. +type clusterInstallationNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ClusterInstallations in the indexer for a given namespace. +func (s clusterInstallationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterInstallation, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ClusterInstallation)) + }) + return ret, err +} + +// Get retrieves the ClusterInstallation from the indexer for a given namespace and name. +func (s clusterInstallationNamespaceLister) Get(name string) (*v1alpha1.ClusterInstallation, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("clusterinstallation"), name) + } + return obj.(*v1alpha1.ClusterInstallation), nil +} diff --git a/pkg/client/listers/mattermost/v1alpha1/expansion_generated.go b/pkg/client/listers/mattermost/v1alpha1/expansion_generated.go new file mode 100644 index 000000000..fb2dba13c --- /dev/null +++ b/pkg/client/listers/mattermost/v1alpha1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// ClusterInstallationListerExpansion allows custom methods to be added to +// ClusterInstallationLister. +type ClusterInstallationListerExpansion interface{} + +// ClusterInstallationNamespaceListerExpansion allows custom methods to be added to +// ClusterInstallationNamespaceLister. +type ClusterInstallationNamespaceListerExpansion interface{} diff --git a/pkg/controller/clusterinstallation/controller.go b/pkg/controller/clusterinstallation/controller.go index 1c9957021..ce9035f0c 100644 --- a/pkg/controller/clusterinstallation/controller.go +++ b/pkg/controller/clusterinstallation/controller.go @@ -2,6 +2,8 @@ package clusterinstallation import ( "context" + "fmt" + "reflect" "github.com/go-logr/logr" appsv1 "k8s.io/api/apps/v1" @@ -24,7 +26,7 @@ import ( mattermostv1alpha1 "github.com/mattermost/mattermost-operator/pkg/apis/mattermost/v1alpha1" ) -var log = logf.Log.WithName("controller_clusterinstallation") +var log = logf.Log.WithName("clusterinstallation.controller") // Add creates a new ClusterInstallation Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. @@ -40,7 +42,7 @@ func newReconciler(mgr manager.Manager) reconcile.Reconciler { // add adds a new Controller to mgr with r as the reconcile.Reconciler func add(mgr manager.Manager, r reconcile.Reconciler) error { // Create a new controller - c, err := controller.New("clusterinstallation-controller", mgr, controller.Options{Reconciler: r}) + c, err := controller.New("clusterinstallation", mgr, controller.Options{Reconciler: r}) if err != nil { return err } @@ -118,71 +120,109 @@ func (r *ReconcileClusterInstallation) Reconcile(request reconcile.Request) (rec return reconcile.Result{}, err } + // Set defaults and update the resource with said defaults if anything is + // different. + originalMattermost := mattermost.DeepCopy() err = mattermost.SetDefaults() if err != nil { return reconcile.Result{}, err } + if !reflect.DeepEqual(originalMattermost.Spec, mattermost.Spec) { + reqLogger.Info(fmt.Sprintf("Updating spec"), + "Old", fmt.Sprintf("%+v", originalMattermost.Spec), + "New", fmt.Sprintf("%+v", mattermost.Spec), + ) + err = r.client.Update(context.TODO(), mattermost) + if err != nil { + reqLogger.Error(err, "failed to update the clusterinstallation spec") + return reconcile.Result{}, err + } + } + + err = r.checkDatabase(mattermost, reqLogger) + if err != nil { + return reconcile.Result{}, err + } + + err = r.checkMinioSecret(mattermost, reqLogger.WithValues("Reconcile.Minio", "secret")) + if err != nil { + return reconcile.Result{}, err + } + err = r.checkMinioDeployment(mattermost, reqLogger.WithValues("Reconcile.Minio", "deployment")) + if err != nil { + return reconcile.Result{}, err + } + err = r.checkMattermost(mattermost, reqLogger) + if err != nil { + return reconcile.Result{}, err + } + + status := mattermostv1alpha1.ClusterInstallationStatus{ + State: mattermostv1alpha1.Running, + Version: mattermost.Spec.Version, + } + if !reflect.DeepEqual(mattermost.Status, status) { + reqLogger.Info(fmt.Sprintf("Updating status"), + "Old", fmt.Sprintf("%+v", mattermost.Status), + "New", fmt.Sprintf("%+v", status), + ) + mattermost.Status = status + err = r.client.Status().Update(context.TODO(), mattermost) + if err != nil { + reqLogger.Error(err, "failed to update the clusterinstallation status") + return reconcile.Result{}, err + } + } + + return reconcile.Result{}, nil +} + +// Object combines the interfaces that all Kubernetes objects must implement. +type Object interface { + runtime.Object + v1.Object +} + +func (r *ReconcileClusterInstallation) checkDatabase(mattermost *mattermostv1alpha1.ClusterInstallation, reqLogger logr.Logger) error { if mattermost.Spec.DatabaseType.ExternalDatabaseSecret != "" { errSecret := r.checkSecret(mattermost.Spec.DatabaseType.ExternalDatabaseSecret, mattermost.Namespace) if errSecret != nil { - return reconcile.Result{}, errSecret + return errSecret } } else { switch mattermost.Spec.DatabaseType.Type { case "mysql": - reqLogger.Info("Reconciling ClusterInstallation MySQL service account") - err = r.checkMySQLServiceAccount(mattermost, reqLogger) + dbLogger := reqLogger.WithValues("Reconcile.Database", "mysql") + + err := r.checkMySQLServiceAccount(mattermost, dbLogger) if err != nil { - return reconcile.Result{}, err + return err } - reqLogger.Info("Reconciling ClusterInstallation MySQL role binding") - err = r.checkMySQLRoleBinding(mattermost, reqLogger) + err = r.checkMySQLRoleBinding(mattermost, dbLogger) if err != nil { - return reconcile.Result{}, err + return err } - reqLogger.Info("Reconciling ClusterInstallation MySQL") - err = r.checkMySQLDeployment(mattermost, reqLogger) + err = r.checkMySQLDeployment(mattermost, dbLogger) if err != nil { - return reconcile.Result{}, err + return err } case "postgres": - reqLogger.Info("Reconciling ClusterInstallation Postgres") - err = r.checkDBPostgresDeployment(mattermost, reqLogger) + dbLogger := reqLogger.WithValues("Reconcile.Database", "postgres") + + err := r.checkDBPostgresDeployment(mattermost, dbLogger) if err != nil { - return reconcile.Result{}, err + return err } case "default": errInvalid := errors.NewInvalid(mattermostv1alpha1.SchemeGroupVersion.WithKind("ClusterInstallation").GroupKind(), "Database type invalid", nil) - return reconcile.Result{}, errInvalid + return errInvalid } } - reqLogger.Info("Reconciling ClusterInstallation Minio secret") - err = r.checkMinioSecret(mattermost, reqLogger) - if err != nil { - return reconcile.Result{}, err - } - reqLogger.Info("Reconciling ClusterInstallation Minio deployment") - err = r.checkMinioDeployment(mattermost, reqLogger) - if err != nil { - return reconcile.Result{}, err - } - - err = r.checkMattermost(mattermost, reqLogger) - if err != nil { - return reconcile.Result{}, err - } - - return reconcile.Result{}, nil -} - -// Object combines the interfaces that all Kubernetes objects must implement. -type Object interface { - runtime.Object - v1.Object + return nil } // createResource creates the provided resource and sets the owner diff --git a/pkg/log/log.go b/pkg/log/log.go index 152d15a37..a21a1757f 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -81,7 +81,11 @@ func (l *logrusLogger) WithValues(keysAndValues ...interface{}) logr.Logger { func (l *logrusLogger) WithName(name string) logr.Logger { newLogger := newLogger(l) - newLogger.name = fmt.Sprintf("%s.%s", l.name, name) + if l.name == "" { + newLogger.name = name + } else { + newLogger.name = fmt.Sprintf("%s.%s", l.name, name) + } return newLogger } diff --git a/vendor/github.com/evanphx/json-patch/LICENSE b/vendor/github.com/evanphx/json-patch/LICENSE new file mode 100644 index 000000000..0eb9b72d8 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2014, Evan Phoenix +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the Evan Phoenix nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/evanphx/json-patch/cmd/json-patch/file_flag.go b/vendor/github.com/evanphx/json-patch/cmd/json-patch/file_flag.go new file mode 100644 index 000000000..fe69d6e2a --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/cmd/json-patch/file_flag.go @@ -0,0 +1,39 @@ +package main + +// Borrowed from Concourse: https://github.com/concourse/atc/blob/master/atccmd/file_flag.go + +import ( + "fmt" + "os" + "path/filepath" +) + +// FileFlag is a flag for passing a path to a file on disk. The file is +// expected to be a file, not a directory, that actually exists. +type FileFlag string + +// UnmarshalFlag implements go-flag's Unmarshaler interface +func (f *FileFlag) UnmarshalFlag(value string) error { + stat, err := os.Stat(value) + if err != nil { + return err + } + + if stat.IsDir() { + return fmt.Errorf("path '%s' is a directory, not a file", value) + } + + abs, err := filepath.Abs(value) + if err != nil { + return err + } + + *f = FileFlag(abs) + + return nil +} + +// Path is the path to the file +func (f FileFlag) Path() string { + return string(f) +} diff --git a/vendor/github.com/evanphx/json-patch/cmd/json-patch/main.go b/vendor/github.com/evanphx/json-patch/cmd/json-patch/main.go new file mode 100644 index 000000000..2be182635 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/cmd/json-patch/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + + jsonpatch "github.com/evanphx/json-patch" + flags "github.com/jessevdk/go-flags" +) + +type opts struct { + PatchFilePaths []FileFlag `long:"patch-file" short:"p" value-name:"PATH" description:"Path to file with one or more operations"` +} + +func main() { + var o opts + _, err := flags.Parse(&o) + if err != nil { + log.Fatalf("error: %s\n", err) + } + + patches := make([]jsonpatch.Patch, len(o.PatchFilePaths)) + + for i, patchFilePath := range o.PatchFilePaths { + var bs []byte + bs, err = ioutil.ReadFile(patchFilePath.Path()) + if err != nil { + log.Fatalf("error reading patch file: %s", err) + } + + var patch jsonpatch.Patch + patch, err = jsonpatch.DecodePatch(bs) + if err != nil { + log.Fatalf("error decoding patch file: %s", err) + } + + patches[i] = patch + } + + doc, err := ioutil.ReadAll(os.Stdin) + if err != nil { + log.Fatalf("error reading from stdin: %s", err) + } + + mdoc := doc + for _, patch := range patches { + mdoc, err = patch.Apply(mdoc) + if err != nil { + log.Fatalf("error applying patch: %s", err) + } + } + + fmt.Printf("%s", mdoc) +} diff --git a/vendor/github.com/evanphx/json-patch/errors.go b/vendor/github.com/evanphx/json-patch/errors.go new file mode 100644 index 000000000..75304b443 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/errors.go @@ -0,0 +1,38 @@ +package jsonpatch + +import "fmt" + +// AccumulatedCopySizeError is an error type returned when the accumulated size +// increase caused by copy operations in a patch operation has exceeded the +// limit. +type AccumulatedCopySizeError struct { + limit int64 + accumulated int64 +} + +// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError. +func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError { + return &AccumulatedCopySizeError{limit: l, accumulated: a} +} + +// Error implements the error interface. +func (a *AccumulatedCopySizeError) Error() string { + return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit) +} + +// ArraySizeError is an error type returned when the array size has exceeded +// the limit. +type ArraySizeError struct { + limit int + size int +} + +// NewArraySizeError returns an ArraySizeError. +func NewArraySizeError(l, s int) *ArraySizeError { + return &ArraySizeError{limit: l, size: s} +} + +// Error implements the error interface. +func (a *ArraySizeError) Error() string { + return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit) +} diff --git a/vendor/github.com/evanphx/json-patch/merge.go b/vendor/github.com/evanphx/json-patch/merge.go new file mode 100644 index 000000000..6806c4c20 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/merge.go @@ -0,0 +1,383 @@ +package jsonpatch + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" +) + +func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode { + curDoc, err := cur.intoDoc() + + if err != nil { + pruneNulls(patch) + return patch + } + + patchDoc, err := patch.intoDoc() + + if err != nil { + return patch + } + + mergeDocs(curDoc, patchDoc, mergeMerge) + + return cur +} + +func mergeDocs(doc, patch *partialDoc, mergeMerge bool) { + for k, v := range *patch { + if v == nil { + if mergeMerge { + (*doc)[k] = nil + } else { + delete(*doc, k) + } + } else { + cur, ok := (*doc)[k] + + if !ok || cur == nil { + pruneNulls(v) + (*doc)[k] = v + } else { + (*doc)[k] = merge(cur, v, mergeMerge) + } + } + } +} + +func pruneNulls(n *lazyNode) { + sub, err := n.intoDoc() + + if err == nil { + pruneDocNulls(sub) + } else { + ary, err := n.intoAry() + + if err == nil { + pruneAryNulls(ary) + } + } +} + +func pruneDocNulls(doc *partialDoc) *partialDoc { + for k, v := range *doc { + if v == nil { + delete(*doc, k) + } else { + pruneNulls(v) + } + } + + return doc +} + +func pruneAryNulls(ary *partialArray) *partialArray { + newAry := []*lazyNode{} + + for _, v := range *ary { + if v != nil { + pruneNulls(v) + newAry = append(newAry, v) + } + } + + *ary = newAry + + return ary +} + +var errBadJSONDoc = fmt.Errorf("Invalid JSON Document") +var errBadJSONPatch = fmt.Errorf("Invalid JSON Patch") +var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents") + +// MergeMergePatches merges two merge patches together, such that +// applying this resulting merged merge patch to a document yields the same +// as merging each merge patch to the document in succession. +func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) { + return doMergePatch(patch1Data, patch2Data, true) +} + +// MergePatch merges the patchData into the docData. +func MergePatch(docData, patchData []byte) ([]byte, error) { + return doMergePatch(docData, patchData, false) +} + +func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) { + doc := &partialDoc{} + + docErr := json.Unmarshal(docData, doc) + + patch := &partialDoc{} + + patchErr := json.Unmarshal(patchData, patch) + + if _, ok := docErr.(*json.SyntaxError); ok { + return nil, errBadJSONDoc + } + + if _, ok := patchErr.(*json.SyntaxError); ok { + return nil, errBadJSONPatch + } + + if docErr == nil && *doc == nil { + return nil, errBadJSONDoc + } + + if patchErr == nil && *patch == nil { + return nil, errBadJSONPatch + } + + if docErr != nil || patchErr != nil { + // Not an error, just not a doc, so we turn straight into the patch + if patchErr == nil { + if mergeMerge { + doc = patch + } else { + doc = pruneDocNulls(patch) + } + } else { + patchAry := &partialArray{} + patchErr = json.Unmarshal(patchData, patchAry) + + if patchErr != nil { + return nil, errBadJSONPatch + } + + pruneAryNulls(patchAry) + + out, patchErr := json.Marshal(patchAry) + + if patchErr != nil { + return nil, errBadJSONPatch + } + + return out, nil + } + } else { + mergeDocs(doc, patch, mergeMerge) + } + + return json.Marshal(doc) +} + +// resemblesJSONArray indicates whether the byte-slice "appears" to be +// a JSON array or not. +// False-positives are possible, as this function does not check the internal +// structure of the array. It only checks that the outer syntax is present and +// correct. +func resemblesJSONArray(input []byte) bool { + input = bytes.TrimSpace(input) + + hasPrefix := bytes.HasPrefix(input, []byte("[")) + hasSuffix := bytes.HasSuffix(input, []byte("]")) + + return hasPrefix && hasSuffix +} + +// CreateMergePatch will return a merge patch document capable of converting +// the original document(s) to the modified document(s). +// The parameters can be bytes of either two JSON Documents, or two arrays of +// JSON documents. +// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07 +func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { + originalResemblesArray := resemblesJSONArray(originalJSON) + modifiedResemblesArray := resemblesJSONArray(modifiedJSON) + + // Do both byte-slices seem like JSON arrays? + if originalResemblesArray && modifiedResemblesArray { + return createArrayMergePatch(originalJSON, modifiedJSON) + } + + // Are both byte-slices are not arrays? Then they are likely JSON objects... + if !originalResemblesArray && !modifiedResemblesArray { + return createObjectMergePatch(originalJSON, modifiedJSON) + } + + // None of the above? Then return an error because of mismatched types. + return nil, errBadMergeTypes +} + +// createObjectMergePatch will return a merge-patch document capable of +// converting the original document to the modified document. +func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { + originalDoc := map[string]interface{}{} + modifiedDoc := map[string]interface{}{} + + err := json.Unmarshal(originalJSON, &originalDoc) + if err != nil { + return nil, errBadJSONDoc + } + + err = json.Unmarshal(modifiedJSON, &modifiedDoc) + if err != nil { + return nil, errBadJSONDoc + } + + dest, err := getDiff(originalDoc, modifiedDoc) + if err != nil { + return nil, err + } + + return json.Marshal(dest) +} + +// createArrayMergePatch will return an array of merge-patch documents capable +// of converting the original document to the modified document for each +// pair of JSON documents provided in the arrays. +// Arrays of mismatched sizes will result in an error. +func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) { + originalDocs := []json.RawMessage{} + modifiedDocs := []json.RawMessage{} + + err := json.Unmarshal(originalJSON, &originalDocs) + if err != nil { + return nil, errBadJSONDoc + } + + err = json.Unmarshal(modifiedJSON, &modifiedDocs) + if err != nil { + return nil, errBadJSONDoc + } + + total := len(originalDocs) + if len(modifiedDocs) != total { + return nil, errBadJSONDoc + } + + result := []json.RawMessage{} + for i := 0; i < len(originalDocs); i++ { + original := originalDocs[i] + modified := modifiedDocs[i] + + patch, err := createObjectMergePatch(original, modified) + if err != nil { + return nil, err + } + + result = append(result, json.RawMessage(patch)) + } + + return json.Marshal(result) +} + +// Returns true if the array matches (must be json types). +// As is idiomatic for go, an empty array is not the same as a nil array. +func matchesArray(a, b []interface{}) bool { + if len(a) != len(b) { + return false + } + if (a == nil && b != nil) || (a != nil && b == nil) { + return false + } + for i := range a { + if !matchesValue(a[i], b[i]) { + return false + } + } + return true +} + +// Returns true if the values matches (must be json types) +// The types of the values must match, otherwise it will always return false +// If two map[string]interface{} are given, all elements must match. +func matchesValue(av, bv interface{}) bool { + if reflect.TypeOf(av) != reflect.TypeOf(bv) { + return false + } + switch at := av.(type) { + case string: + bt := bv.(string) + if bt == at { + return true + } + case float64: + bt := bv.(float64) + if bt == at { + return true + } + case bool: + bt := bv.(bool) + if bt == at { + return true + } + case nil: + // Both nil, fine. + return true + case map[string]interface{}: + bt := bv.(map[string]interface{}) + for key := range at { + if !matchesValue(at[key], bt[key]) { + return false + } + } + for key := range bt { + if !matchesValue(at[key], bt[key]) { + return false + } + } + return true + case []interface{}: + bt := bv.([]interface{}) + return matchesArray(at, bt) + } + return false +} + +// getDiff returns the (recursive) difference between a and b as a map[string]interface{}. +func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) { + into := map[string]interface{}{} + for key, bv := range b { + av, ok := a[key] + // value was added + if !ok { + into[key] = bv + continue + } + // If types have changed, replace completely + if reflect.TypeOf(av) != reflect.TypeOf(bv) { + into[key] = bv + continue + } + // Types are the same, compare values + switch at := av.(type) { + case map[string]interface{}: + bt := bv.(map[string]interface{}) + dst := make(map[string]interface{}, len(bt)) + dst, err := getDiff(at, bt) + if err != nil { + return nil, err + } + if len(dst) > 0 { + into[key] = dst + } + case string, float64, bool: + if !matchesValue(av, bv) { + into[key] = bv + } + case []interface{}: + bt := bv.([]interface{}) + if !matchesArray(at, bt) { + into[key] = bv + } + case nil: + switch bv.(type) { + case nil: + // Both nil, fine. + default: + into[key] = bv + } + default: + panic(fmt.Sprintf("Unknown type:%T in key %s", av, key)) + } + } + // Now add all deleted values as nil + for key := range a { + _, found := b[key] + if !found { + into[key] = nil + } + } + return into, nil +} diff --git a/vendor/github.com/evanphx/json-patch/patch.go b/vendor/github.com/evanphx/json-patch/patch.go new file mode 100644 index 000000000..c9cf59021 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/patch.go @@ -0,0 +1,696 @@ +package jsonpatch + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" +) + +const ( + eRaw = iota + eDoc + eAry +) + +var ( + // SupportNegativeIndices decides whether to support non-standard practice of + // allowing negative indices to mean indices starting at the end of an array. + // Default to true. + SupportNegativeIndices bool = true + // AccumulatedCopySizeLimit limits the total size increase in bytes caused by + // "copy" operations in a patch. + AccumulatedCopySizeLimit int64 = 0 +) + +type lazyNode struct { + raw *json.RawMessage + doc partialDoc + ary partialArray + which int +} + +type operation map[string]*json.RawMessage + +// Patch is an ordered collection of operations. +type Patch []operation + +type partialDoc map[string]*lazyNode +type partialArray []*lazyNode + +type container interface { + get(key string) (*lazyNode, error) + set(key string, val *lazyNode) error + add(key string, val *lazyNode) error + remove(key string) error +} + +func newLazyNode(raw *json.RawMessage) *lazyNode { + return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw} +} + +func (n *lazyNode) MarshalJSON() ([]byte, error) { + switch n.which { + case eRaw: + return json.Marshal(n.raw) + case eDoc: + return json.Marshal(n.doc) + case eAry: + return json.Marshal(n.ary) + default: + return nil, fmt.Errorf("Unknown type") + } +} + +func (n *lazyNode) UnmarshalJSON(data []byte) error { + dest := make(json.RawMessage, len(data)) + copy(dest, data) + n.raw = &dest + n.which = eRaw + return nil +} + +func deepCopy(src *lazyNode) (*lazyNode, int, error) { + if src == nil { + return nil, 0, nil + } + a, err := src.MarshalJSON() + if err != nil { + return nil, 0, err + } + sz := len(a) + ra := make(json.RawMessage, sz) + copy(ra, a) + return newLazyNode(&ra), sz, nil +} + +func (n *lazyNode) intoDoc() (*partialDoc, error) { + if n.which == eDoc { + return &n.doc, nil + } + + if n.raw == nil { + return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial document") + } + + err := json.Unmarshal(*n.raw, &n.doc) + + if err != nil { + return nil, err + } + + n.which = eDoc + return &n.doc, nil +} + +func (n *lazyNode) intoAry() (*partialArray, error) { + if n.which == eAry { + return &n.ary, nil + } + + if n.raw == nil { + return nil, fmt.Errorf("Unable to unmarshal nil pointer as partial array") + } + + err := json.Unmarshal(*n.raw, &n.ary) + + if err != nil { + return nil, err + } + + n.which = eAry + return &n.ary, nil +} + +func (n *lazyNode) compact() []byte { + buf := &bytes.Buffer{} + + if n.raw == nil { + return nil + } + + err := json.Compact(buf, *n.raw) + + if err != nil { + return *n.raw + } + + return buf.Bytes() +} + +func (n *lazyNode) tryDoc() bool { + if n.raw == nil { + return false + } + + err := json.Unmarshal(*n.raw, &n.doc) + + if err != nil { + return false + } + + n.which = eDoc + return true +} + +func (n *lazyNode) tryAry() bool { + if n.raw == nil { + return false + } + + err := json.Unmarshal(*n.raw, &n.ary) + + if err != nil { + return false + } + + n.which = eAry + return true +} + +func (n *lazyNode) equal(o *lazyNode) bool { + if n.which == eRaw { + if !n.tryDoc() && !n.tryAry() { + if o.which != eRaw { + return false + } + + return bytes.Equal(n.compact(), o.compact()) + } + } + + if n.which == eDoc { + if o.which == eRaw { + if !o.tryDoc() { + return false + } + } + + if o.which != eDoc { + return false + } + + for k, v := range n.doc { + ov, ok := o.doc[k] + + if !ok { + return false + } + + if v == nil && ov == nil { + continue + } + + if !v.equal(ov) { + return false + } + } + + return true + } + + if o.which != eAry && !o.tryAry() { + return false + } + + if len(n.ary) != len(o.ary) { + return false + } + + for idx, val := range n.ary { + if !val.equal(o.ary[idx]) { + return false + } + } + + return true +} + +func (o operation) kind() string { + if obj, ok := o["op"]; ok && obj != nil { + var op string + + err := json.Unmarshal(*obj, &op) + + if err != nil { + return "unknown" + } + + return op + } + + return "unknown" +} + +func (o operation) path() string { + if obj, ok := o["path"]; ok && obj != nil { + var op string + + err := json.Unmarshal(*obj, &op) + + if err != nil { + return "unknown" + } + + return op + } + + return "unknown" +} + +func (o operation) from() string { + if obj, ok := o["from"]; ok && obj != nil { + var op string + + err := json.Unmarshal(*obj, &op) + + if err != nil { + return "unknown" + } + + return op + } + + return "unknown" +} + +func (o operation) value() *lazyNode { + if obj, ok := o["value"]; ok { + return newLazyNode(obj) + } + + return nil +} + +func isArray(buf []byte) bool { +Loop: + for _, c := range buf { + switch c { + case ' ': + case '\n': + case '\t': + continue + case '[': + return true + default: + break Loop + } + } + + return false +} + +func findObject(pd *container, path string) (container, string) { + doc := *pd + + split := strings.Split(path, "/") + + if len(split) < 2 { + return nil, "" + } + + parts := split[1 : len(split)-1] + + key := split[len(split)-1] + + var err error + + for _, part := range parts { + + next, ok := doc.get(decodePatchKey(part)) + + if next == nil || ok != nil { + return nil, "" + } + + if isArray(*next.raw) { + doc, err = next.intoAry() + + if err != nil { + return nil, "" + } + } else { + doc, err = next.intoDoc() + + if err != nil { + return nil, "" + } + } + } + + return doc, decodePatchKey(key) +} + +func (d *partialDoc) set(key string, val *lazyNode) error { + (*d)[key] = val + return nil +} + +func (d *partialDoc) add(key string, val *lazyNode) error { + (*d)[key] = val + return nil +} + +func (d *partialDoc) get(key string) (*lazyNode, error) { + return (*d)[key], nil +} + +func (d *partialDoc) remove(key string) error { + _, ok := (*d)[key] + if !ok { + return fmt.Errorf("Unable to remove nonexistent key: %s", key) + } + + delete(*d, key) + return nil +} + +// set should only be used to implement the "replace" operation, so "key" must +// be an already existing index in "d". +func (d *partialArray) set(key string, val *lazyNode) error { + idx, err := strconv.Atoi(key) + if err != nil { + return err + } + (*d)[idx] = val + return nil +} + +func (d *partialArray) add(key string, val *lazyNode) error { + if key == "-" { + *d = append(*d, val) + return nil + } + + idx, err := strconv.Atoi(key) + if err != nil { + return err + } + + sz := len(*d) + 1 + + ary := make([]*lazyNode, sz) + + cur := *d + + if idx >= len(ary) { + return fmt.Errorf("Unable to access invalid index: %d", idx) + } + + if SupportNegativeIndices { + if idx < -len(ary) { + return fmt.Errorf("Unable to access invalid index: %d", idx) + } + + if idx < 0 { + idx += len(ary) + } + } + + copy(ary[0:idx], cur[0:idx]) + ary[idx] = val + copy(ary[idx+1:], cur[idx:]) + + *d = ary + return nil +} + +func (d *partialArray) get(key string) (*lazyNode, error) { + idx, err := strconv.Atoi(key) + + if err != nil { + return nil, err + } + + if idx >= len(*d) { + return nil, fmt.Errorf("Unable to access invalid index: %d", idx) + } + + return (*d)[idx], nil +} + +func (d *partialArray) remove(key string) error { + idx, err := strconv.Atoi(key) + if err != nil { + return err + } + + cur := *d + + if idx >= len(cur) { + return fmt.Errorf("Unable to access invalid index: %d", idx) + } + + if SupportNegativeIndices { + if idx < -len(cur) { + return fmt.Errorf("Unable to access invalid index: %d", idx) + } + + if idx < 0 { + idx += len(cur) + } + } + + ary := make([]*lazyNode, len(cur)-1) + + copy(ary[0:idx], cur[0:idx]) + copy(ary[idx:], cur[idx+1:]) + + *d = ary + return nil + +} + +func (p Patch) add(doc *container, op operation) error { + path := op.path() + + con, key := findObject(doc, path) + + if con == nil { + return fmt.Errorf("jsonpatch add operation does not apply: doc is missing path: \"%s\"", path) + } + + return con.add(key, op.value()) +} + +func (p Patch) remove(doc *container, op operation) error { + path := op.path() + + con, key := findObject(doc, path) + + if con == nil { + return fmt.Errorf("jsonpatch remove operation does not apply: doc is missing path: \"%s\"", path) + } + + return con.remove(key) +} + +func (p Patch) replace(doc *container, op operation) error { + path := op.path() + + con, key := findObject(doc, path) + + if con == nil { + return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing path: %s", path) + } + + _, ok := con.get(key) + if ok != nil { + return fmt.Errorf("jsonpatch replace operation does not apply: doc is missing key: %s", path) + } + + return con.set(key, op.value()) +} + +func (p Patch) move(doc *container, op operation) error { + from := op.from() + + con, key := findObject(doc, from) + + if con == nil { + return fmt.Errorf("jsonpatch move operation does not apply: doc is missing from path: %s", from) + } + + val, err := con.get(key) + if err != nil { + return err + } + + err = con.remove(key) + if err != nil { + return err + } + + path := op.path() + + con, key = findObject(doc, path) + + if con == nil { + return fmt.Errorf("jsonpatch move operation does not apply: doc is missing destination path: %s", path) + } + + return con.add(key, val) +} + +func (p Patch) test(doc *container, op operation) error { + path := op.path() + + con, key := findObject(doc, path) + + if con == nil { + return fmt.Errorf("jsonpatch test operation does not apply: is missing path: %s", path) + } + + val, err := con.get(key) + + if err != nil { + return err + } + + if val == nil { + if op.value().raw == nil { + return nil + } + return fmt.Errorf("Testing value %s failed", path) + } else if op.value() == nil { + return fmt.Errorf("Testing value %s failed", path) + } + + if val.equal(op.value()) { + return nil + } + + return fmt.Errorf("Testing value %s failed", path) +} + +func (p Patch) copy(doc *container, op operation, accumulatedCopySize *int64) error { + from := op.from() + + con, key := findObject(doc, from) + + if con == nil { + return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing from path: %s", from) + } + + val, err := con.get(key) + if err != nil { + return err + } + + path := op.path() + + con, key = findObject(doc, path) + + if con == nil { + return fmt.Errorf("jsonpatch copy operation does not apply: doc is missing destination path: %s", path) + } + + valCopy, sz, err := deepCopy(val) + if err != nil { + return err + } + (*accumulatedCopySize) += int64(sz) + if AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > AccumulatedCopySizeLimit { + return NewAccumulatedCopySizeError(AccumulatedCopySizeLimit, *accumulatedCopySize) + } + + return con.add(key, valCopy) +} + +// Equal indicates if 2 JSON documents have the same structural equality. +func Equal(a, b []byte) bool { + ra := make(json.RawMessage, len(a)) + copy(ra, a) + la := newLazyNode(&ra) + + rb := make(json.RawMessage, len(b)) + copy(rb, b) + lb := newLazyNode(&rb) + + return la.equal(lb) +} + +// DecodePatch decodes the passed JSON document as an RFC 6902 patch. +func DecodePatch(buf []byte) (Patch, error) { + var p Patch + + err := json.Unmarshal(buf, &p) + + if err != nil { + return nil, err + } + + return p, nil +} + +// Apply mutates a JSON document according to the patch, and returns the new +// document. +func (p Patch) Apply(doc []byte) ([]byte, error) { + return p.ApplyIndent(doc, "") +} + +// ApplyIndent mutates a JSON document according to the patch, and returns the new +// document indented. +func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) { + var pd container + if doc[0] == '[' { + pd = &partialArray{} + } else { + pd = &partialDoc{} + } + + err := json.Unmarshal(doc, pd) + + if err != nil { + return nil, err + } + + err = nil + + var accumulatedCopySize int64 + + for _, op := range p { + switch op.kind() { + case "add": + err = p.add(&pd, op) + case "remove": + err = p.remove(&pd, op) + case "replace": + err = p.replace(&pd, op) + case "move": + err = p.move(&pd, op) + case "test": + err = p.test(&pd, op) + case "copy": + err = p.copy(&pd, op, &accumulatedCopySize) + default: + err = fmt.Errorf("Unexpected kind: %s", op.kind()) + } + + if err != nil { + return nil, err + } + } + + if indent != "" { + return json.MarshalIndent(pd, "", indent) + } + + return json.Marshal(pd) +} + +// From http://tools.ietf.org/html/rfc6901#section-4 : +// +// Evaluation of each reference token begins by decoding any escaped +// character sequence. This is performed by first transforming any +// occurrence of the sequence '~1' to '/', and then transforming any +// occurrence of the sequence '~0' to '~'. + +var ( + rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~") +) + +func decodePatchKey(k string) string { + return rfc6901Decoder.Replace(k) +}