From 76eb8fa8c9a7852964984997d98650574288c058 Mon Sep 17 00:00:00 2001 From: Ace Eldeib Date: Thu, 2 Apr 2020 02:04:43 -0700 Subject: [PATCH] feat: poc aks provider --- api/v1alpha3/azuremanagedcluster_types.go | 99 ++++++++ api/v1alpha3/azuremanagedmachinepool_types.go | 86 +++++++ api/v1alpha3/zz_generated.deepcopy.go | 222 ++++++++++++++++++ cloud/interfaces.go | 5 + cloud/scope/managedcluster.go | 133 +++++++++++ cloud/services/agentpools/agentpools.go | 120 ++++++++++ cloud/services/agentpools/client.go | 86 +++++++ cloud/services/agentpools/service.go | 33 +++ cloud/services/managedclusters/client.go | 102 ++++++++ .../managedclusters/managedclusters.go | 184 +++++++++++++++ cloud/services/managedclusters/service.go | 33 +++ cloud/services/scalesets/client.go | 65 +++++ cloud/services/scalesets/service.go | 31 +++ cloud/services/scalesets/vmss.go | 36 +++ cloud/services/scalesetvms/client.go | 66 ++++++ cloud/services/scalesetvms/service.go | 31 +++ cloud/services/scalesetvms/vmss.go | 37 +++ ...cluster.x-k8s.io_azuremanagedclusters.yaml | 138 +++++++++++ ...ter.x-k8s.io_azuremanagedmachinepools.yaml | 95 ++++++++ config/crd/kustomization.yaml | 7 + .../cainjection_in_azuremanagedclusters.yaml | 8 + ...injection_in_azuremanagedmachinepools.yaml | 8 + .../webhook_in_azuremanagedclusters.yaml | 19 ++ .../webhook_in_azuremanagedmachinepools.yaml | 19 ++ config/manager/manager_image_patch.yaml | 2 +- config/rbac/role.yaml | 52 ++++ controllers/azurecluster_controller.go | 1 + controllers/azuremanagedcluster_controller.go | 207 ++++++++++++++++ controllers/azuremanagedcluster_reconciler.go | 158 +++++++++++++ .../azuremanagedmachinepool_controller.go | 208 ++++++++++++++++ .../azuremanagedmachinepool_reconciler.go | 138 +++++++++++ go.mod | 1 + go.sum | 131 +---------- main.go | 21 +- 34 files changed, 2451 insertions(+), 131 deletions(-) create mode 100644 api/v1alpha3/azuremanagedcluster_types.go create mode 100644 api/v1alpha3/azuremanagedmachinepool_types.go create mode 100644 cloud/scope/managedcluster.go create mode 100644 cloud/services/agentpools/agentpools.go create mode 100644 cloud/services/agentpools/client.go create mode 100644 cloud/services/agentpools/service.go create mode 100644 cloud/services/managedclusters/client.go create mode 100644 cloud/services/managedclusters/managedclusters.go create mode 100644 cloud/services/managedclusters/service.go create mode 100644 cloud/services/scalesets/client.go create mode 100644 cloud/services/scalesets/service.go create mode 100644 cloud/services/scalesets/vmss.go create mode 100644 cloud/services/scalesetvms/client.go create mode 100644 cloud/services/scalesetvms/service.go create mode 100644 cloud/services/scalesetvms/vmss.go create mode 100644 config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedclusters.yaml create mode 100644 config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml create mode 100644 config/crd/patches/cainjection_in_azuremanagedclusters.yaml create mode 100644 config/crd/patches/cainjection_in_azuremanagedmachinepools.yaml create mode 100644 config/crd/patches/webhook_in_azuremanagedclusters.yaml create mode 100644 config/crd/patches/webhook_in_azuremanagedmachinepools.yaml create mode 100644 controllers/azuremanagedcluster_controller.go create mode 100644 controllers/azuremanagedcluster_reconciler.go create mode 100644 controllers/azuremanagedmachinepool_controller.go create mode 100644 controllers/azuremanagedmachinepool_reconciler.go diff --git a/api/v1alpha3/azuremanagedcluster_types.go b/api/v1alpha3/azuremanagedcluster_types.go new file mode 100644 index 000000000000..8651b6f9aa66 --- /dev/null +++ b/api/v1alpha3/azuremanagedcluster_types.go @@ -0,0 +1,99 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" +) + +// AzureManagedClusterSpec defines the desired state of AzureManagedCluster +type AzureManagedClusterSpec struct { + // Version defines the desired Kubernetes version. + // +kubebuilder:validation:MinLength:=2 + // +kubebuilder:validation:Pattern:=^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)([-0-9a-zA-Z_\.+]*)?$ + Version string `json:"version"` + + // ResourceGroup is the name of the Azure resource group for this AKS Cluster. + ResourceGroup string `json:"resourceGroup"` + + // Location is a string matching one of the canonical Azure region names. Examples: "westus2", "eastus". + Location string `json:"location"` + + // ControlPlaneEndpoint represents the endpoint used to communicate with the control plane. + // +optional + ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"` + + // AdditionalTags is an optional set of tags to add to Azure resources managed by the Azure provider, in addition to the + // ones added by default. + // +optional + AdditionalTags Tags `json:"additionalTags,omitempty"` + + // LoadBalancerSKU for the managed cluster. Possible values include: 'Standard', 'Basic'. Defaults to standard. + // +kubebuilder:validation:Enum=Standard;Basic + LoadBalancerSKU *string `json:"loadBalancerSku,omitempty"` + + // NetworkPlugin used for building Kubernetes network. Possible values include: 'Azure', 'Kubenet'. Defaults to Azure. + // +kubebuilder:validation:Enum=Azure;Kubenet + NetworkPlugin *string `json:"networkPlugin,omitempty"` + + // NetworkPolicy used for building Kubernetes network. Possible values include: 'NetworkPolicyCalico', 'NetworkPolicyAzure' + // +kubebuilder:validation:Enum=NetworkPolicyCalico;NetworkPolicyAzure + NetworkPolicy *string `json:"networkPolicy,omitempty"` + + // SSHPublicKey is a string literal containing an ssh public key. + SSHPublicKey string `json:"sshPublicKey"` + + // DefaultPoolRef is the specification for the default pool, without which an AKS cluster cannot be created. + // TODO(ace): consider defaulting and making optional pointer? + DefaultPoolRef corev1.LocalObjectReference `json:"defaultPoolRef"` +} + +// AzureManagedClusterStatus defines the observed state of AzureManagedCluster +type AzureManagedClusterStatus struct { + // Ready is true when the provider resource is ready. + // +optional + Ready bool `json:"ready,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=azuremanagedclusters,scope=Namespaced,categories=cluster-api,shortName=amc +// +kubebuilder:storageversion +// +kubebuilder:subresource:status + +// AzureManagedCluster is the Schema for the azuremanagedclusters API +type AzureManagedCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AzureManagedClusterSpec `json:"spec,omitempty"` + Status AzureManagedClusterStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// AzureManagedClusterList contains a list of AzureManagedCluster +type AzureManagedClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AzureManagedCluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AzureManagedCluster{}, &AzureManagedClusterList{}) +} diff --git a/api/v1alpha3/azuremanagedmachinepool_types.go b/api/v1alpha3/azuremanagedmachinepool_types.go new file mode 100644 index 000000000000..62416038a603 --- /dev/null +++ b/api/v1alpha3/azuremanagedmachinepool_types.go @@ -0,0 +1,86 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + capierrors "sigs.k8s.io/cluster-api/errors" +) + +// AzureManagedMachinePoolSpec defines the desired state of AzureManagedMachinePool +type AzureManagedMachinePoolSpec struct { + // SKU is the size of the VMs in the node pool. + SKU string `json:"sku"` + + // OSDiskSizeGB is the disk size for every machine in this master/agent pool. + // If you specify 0, it will apply the default osDisk size according to the vmSize specified. + OSDiskSizeGB *int32 `json:"osDiskSizeGB,omitempty"` + + // ProviderIDList is the unique identifier as specified by the cloud provider. + // +optional + ProviderIDList []string `json:"providerIDList,omitempty"` +} + +// AzureManagedMachinePoolStatus defines the observed state of AzureManagedMachinePool +type AzureManagedMachinePoolStatus struct { + // Replicas is the most recently observed number of replicas. + // +optional + Replicas int32 `json:"replicas"` + + // Any transient errors that occur during the reconciliation of Machines + // can be added as events to the Machine object and/or logged in the + // controller's output. + // +optional + ErrorReason *capierrors.MachineStatusError `json:"errorReason,omitempty"` + + // Any transient errors that occur during the reconciliation of Machines + // can be added as events to the Machine object and/or logged in the + // controller's output. + // +optional + ErrorMessage *string `json:"errorMessage,omitempty"` + + // Ready is true when the provider resource is ready. + // +optional + Ready bool `json:"ready"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=azuremanagedmachinepools,scope=Namespaced,categories=cluster-api,shortName=ammp +// +kubebuilder:storageversion +// +kubebuilder:subresource:status + +// AzureManagedMachinePool is the Schema for the azuremanagedmachinepools API +type AzureManagedMachinePool struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AzureManagedMachinePoolSpec `json:"spec,omitempty"` + Status AzureManagedMachinePoolStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// AzureManagedMachinePoolList contains a list of AzureManagedMachinePool +type AzureManagedMachinePoolList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AzureManagedMachinePool `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AzureManagedMachinePool{}, &AzureManagedMachinePoolList{}) +} diff --git a/api/v1alpha3/zz_generated.deepcopy.go b/api/v1alpha3/zz_generated.deepcopy.go index dc0be6bb61e1..c955aa0e1530 100644 --- a/api/v1alpha3/zz_generated.deepcopy.go +++ b/api/v1alpha3/zz_generated.deepcopy.go @@ -386,6 +386,228 @@ func (in *AzureMachineTemplateSpec) DeepCopy() *AzureMachineTemplateSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedCluster) DeepCopyInto(out *AzureManagedCluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedCluster. +func (in *AzureManagedCluster) DeepCopy() *AzureManagedCluster { + if in == nil { + return nil + } + out := new(AzureManagedCluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AzureManagedCluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedClusterList) DeepCopyInto(out *AzureManagedClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AzureManagedCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedClusterList. +func (in *AzureManagedClusterList) DeepCopy() *AzureManagedClusterList { + if in == nil { + return nil + } + out := new(AzureManagedClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AzureManagedClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedClusterSpec) DeepCopyInto(out *AzureManagedClusterSpec) { + *out = *in + out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + if in.AdditionalTags != nil { + in, out := &in.AdditionalTags, &out.AdditionalTags + *out = make(Tags, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.LoadBalancerSKU != nil { + in, out := &in.LoadBalancerSKU, &out.LoadBalancerSKU + *out = new(string) + **out = **in + } + if in.NetworkPlugin != nil { + in, out := &in.NetworkPlugin, &out.NetworkPlugin + *out = new(string) + **out = **in + } + if in.NetworkPolicy != nil { + in, out := &in.NetworkPolicy, &out.NetworkPolicy + *out = new(string) + **out = **in + } + out.DefaultPoolRef = in.DefaultPoolRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedClusterSpec. +func (in *AzureManagedClusterSpec) DeepCopy() *AzureManagedClusterSpec { + if in == nil { + return nil + } + out := new(AzureManagedClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedClusterStatus) DeepCopyInto(out *AzureManagedClusterStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedClusterStatus. +func (in *AzureManagedClusterStatus) DeepCopy() *AzureManagedClusterStatus { + if in == nil { + return nil + } + out := new(AzureManagedClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedMachinePool) DeepCopyInto(out *AzureManagedMachinePool) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedMachinePool. +func (in *AzureManagedMachinePool) DeepCopy() *AzureManagedMachinePool { + if in == nil { + return nil + } + out := new(AzureManagedMachinePool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AzureManagedMachinePool) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedMachinePoolList) DeepCopyInto(out *AzureManagedMachinePoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AzureManagedMachinePool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedMachinePoolList. +func (in *AzureManagedMachinePoolList) DeepCopy() *AzureManagedMachinePoolList { + if in == nil { + return nil + } + out := new(AzureManagedMachinePoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AzureManagedMachinePoolList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedMachinePoolSpec) DeepCopyInto(out *AzureManagedMachinePoolSpec) { + *out = *in + if in.OSDiskSizeGB != nil { + in, out := &in.OSDiskSizeGB, &out.OSDiskSizeGB + *out = new(int32) + **out = **in + } + if in.ProviderIDList != nil { + in, out := &in.ProviderIDList, &out.ProviderIDList + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedMachinePoolSpec. +func (in *AzureManagedMachinePoolSpec) DeepCopy() *AzureManagedMachinePoolSpec { + if in == nil { + return nil + } + out := new(AzureManagedMachinePoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureManagedMachinePoolStatus) DeepCopyInto(out *AzureManagedMachinePoolStatus) { + *out = *in + if in.ErrorReason != nil { + in, out := &in.ErrorReason, &out.ErrorReason + *out = new(errors.MachineStatusError) + **out = **in + } + if in.ErrorMessage != nil { + in, out := &in.ErrorMessage, &out.ErrorMessage + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureManagedMachinePoolStatus. +func (in *AzureManagedMachinePoolStatus) DeepCopy() *AzureManagedMachinePoolStatus { + if in == nil { + return nil + } + out := new(AzureManagedMachinePoolStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureMarketplaceImage) DeepCopyInto(out *AzureMarketplaceImage) { *out = *in diff --git a/cloud/interfaces.go b/cloud/interfaces.go index 8ddf4df9cbc7..4b0bc45bdcc8 100644 --- a/cloud/interfaces.go +++ b/cloud/interfaces.go @@ -35,3 +35,8 @@ type GetterService interface { Reconcile(ctx context.Context, spec interface{}) error Delete(ctx context.Context, spec interface{}) error } + +type CredentialGetter interface { + GetterService + GetCredentials(ctx context.Context, spec interface{}) ([]byte, error) +} diff --git a/cloud/scope/managedcluster.go b/cloud/scope/managedcluster.go new file mode 100644 index 000000000000..5933ef9139dc --- /dev/null +++ b/cloud/scope/managedcluster.go @@ -0,0 +1,133 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scope + +import ( + "context" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + "k8s.io/klog/klogr" + infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + "sigs.k8s.io/cluster-api/util/patch" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// TODO(ace): cleanup this file + +// ManagedClusterScopeParams defines the input parameters used to create a new Scope. +type ManagedClusterScopeParams struct { + AzureClients + Client client.Client + Logger logr.Logger + Cluster *clusterv1.Cluster + AzureManagedCluster *infrav1.AzureManagedCluster + Context context.Context +} + +// NewManagedClusterScope creates a new Scope from the supplied parameters. +// This is meant to be called for each reconcile iteration. +func NewManagedClusterScope(params ManagedClusterScopeParams) (*ManagedClusterScope, error) { + if params.Cluster == nil { + return nil, errors.New("failed to generate new scope from nil Cluster") + } + if params.AzureManagedCluster == nil { + return nil, errors.New("failed to generate new scope from nil AzureManagedCluster") + } + + if params.Logger == nil { + params.Logger = klogr.New() + } + + err := params.AzureClients.setCredentials() + if err != nil { + return nil, errors.Wrap(err, "failed to create Azure session") + } + + helper, err := patch.NewHelper(params.AzureManagedCluster, params.Client) + if err != nil { + return nil, errors.Wrap(err, "failed to init patch helper") + } + return &ManagedClusterScope{ + Logger: params.Logger, + client: params.Client, + AzureClients: params.AzureClients, + Cluster: params.Cluster, + AzureManagedCluster: params.AzureManagedCluster, + patchHelper: helper, + Context: context.Background(), + }, nil +} + +// ManagedClusterScope defines the basic context for an actuator to operate upon. +type ManagedClusterScope struct { + logr.Logger + client client.Client + patchHelper *patch.Helper + + AzureClients + Cluster *clusterv1.Cluster + AzureManagedCluster *infrav1.AzureManagedCluster + Context context.Context +} + +// ResourceGroup returns the cluster resource group. +func (s *ManagedClusterScope) ResourceGroup() string { + return s.AzureManagedCluster.Spec.ResourceGroup +} + +// Name returns the cluster name. +func (s *ManagedClusterScope) Name() string { + return s.Cluster.Name +} + +// Namespace returns the cluster namespace. +func (s *ManagedClusterScope) Namespace() string { + return s.Cluster.Namespace +} + +// Location returns the cluster location. +func (s *ManagedClusterScope) Location() string { + return s.AzureManagedCluster.Spec.Location +} + +// ListOptionsLabelSelector returns a ListOptions with a label selector for clusterName. +func (s *ManagedClusterScope) ListOptionsLabelSelector() client.ListOption { + return client.MatchingLabels(map[string]string{ + clusterv1.ClusterLabelName: s.Cluster.Name, + }) +} + +// PatchObject persists the cluster configuration and status. +func (s *ManagedClusterScope) PatchObject() error { + return s.patchHelper.Patch(context.TODO(), s.AzureManagedCluster) +} + +// Close closes the current scope persisting the cluster configuration and status. +func (s *ManagedClusterScope) Close() error { + return s.patchHelper.Patch(context.TODO(), s.AzureManagedCluster) +} + +// AdditionalTags returns AdditionalTags from the scope's AzureManagedCluster. +func (s *ManagedClusterScope) AdditionalTags() infrav1.Tags { + tags := make(infrav1.Tags) + if s.AzureManagedCluster.Spec.AdditionalTags != nil { + tags = s.AzureManagedCluster.Spec.AdditionalTags.DeepCopy() + } + return tags +} diff --git a/cloud/services/agentpools/agentpools.go b/cloud/services/agentpools/agentpools.go new file mode 100644 index 000000000000..ac8a3253ff60 --- /dev/null +++ b/cloud/services/agentpools/agentpools.go @@ -0,0 +1,120 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package agentpools + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice" + "github.com/google/go-cmp/cmp" + "github.com/pkg/errors" + "k8s.io/klog" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" +) + +// Spec contains properties to create a agent pool. +type Spec struct { + Name string + ResourceGroup string + Cluster string + SKU string + Replicas int32 + OSDiskSizeGB int32 +} + +// Get fetches a agent pool from Azure. +func (s *Service) Get(ctx context.Context, spec interface{}) (interface{}, error) { + agentPoolSpec, ok := spec.(*Spec) + if !ok { + return containerservice.AgentPool{}, errors.New("expected agent pool specification") + } + return s.Client.Get(ctx, agentPoolSpec.ResourceGroup, agentPoolSpec.Cluster, agentPoolSpec.Name) +} + +// Reconcile idempotently creates or updates a agent pool, if possible. +func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { + agentPoolSpec, ok := spec.(*Spec) + if !ok { + return errors.New("expected agent pool specification") + } + + profile := containerservice.AgentPool{ + ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ + VMSize: containerservice.VMSizeTypes(agentPoolSpec.SKU), + OsDiskSizeGB: &agentPoolSpec.OSDiskSizeGB, + Count: &agentPoolSpec.Replicas, + Type: containerservice.VirtualMachineScaleSets, + }, + } + + existingSpec, err := s.Get(ctx, spec) + existingPool, ok := existingSpec.(containerservice.AgentPool) + if !ok { + return errors.New("expected agent pool specification") + } + + if err == nil { + existingProfile := containerservice.AgentPool{ + ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ + VMSize: existingPool.ManagedClusterAgentPoolProfileProperties.VMSize, + OsDiskSizeGB: existingPool.ManagedClusterAgentPoolProfileProperties.OsDiskSizeGB, + Count: existingPool.ManagedClusterAgentPoolProfileProperties.Count, + Type: containerservice.VirtualMachineScaleSets, + }, + } + + diff := cmp.Diff(profile, existingProfile) + if diff != "" { + fmt.Printf("update required (+new -old):\n%s", diff) + err = s.Client.CreateOrUpdate(ctx, agentPoolSpec.ResourceGroup, agentPoolSpec.Cluster, agentPoolSpec.Name, profile) + if err != nil { + return fmt.Errorf("failed to create or update agent pool, %v", err) + } + } else { + fmt.Println("normalized and desired managed cluster matched, no update needed (go-cmp)") + } + } else if azure.ResourceNotFound(err) { + err = s.Client.CreateOrUpdate(ctx, agentPoolSpec.ResourceGroup, agentPoolSpec.Cluster, agentPoolSpec.Name, profile) + if err != nil { + return fmt.Errorf("failed to create or update agent pool, %v", err) + } + } + + return nil +} + +// Delete deletes the virtual network with the provided name. +func (s *Service) Delete(ctx context.Context, spec interface{}) error { + agentPoolSpec, ok := spec.(*Spec) + if !ok { + return errors.New("expected agent pool specification") + } + + klog.V(2).Infof("deleting agent pool %s ", agentPoolSpec.Name) + err := s.Client.Delete(ctx, agentPoolSpec.ResourceGroup, agentPoolSpec.Cluster, agentPoolSpec.Name) + if err != nil && azure.ResourceNotFound(err) { + // already deleted + return nil + } + if err != nil { + return errors.Wrapf(err, "failed to delete agent pool %s in resource group %s", agentPoolSpec.Name, agentPoolSpec.ResourceGroup) + } + + klog.V(2).Infof("successfully deleted agent pool %s ", agentPoolSpec.Name) + return nil +} diff --git a/cloud/services/agentpools/client.go b/cloud/services/agentpools/client.go new file mode 100644 index 000000000000..b00a5d82a44c --- /dev/null +++ b/cloud/services/agentpools/client.go @@ -0,0 +1,86 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package agentpools + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice" + "github.com/Azure/go-autorest/autorest" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" +) + +// Client wraps go-sdk +type Client interface { + Get(context.Context, string, string, string) (containerservice.AgentPool, error) + CreateOrUpdate(context.Context, string, string, string, containerservice.AgentPool) error + Delete(context.Context, string, string, string) error +} + +// AzureClient contains the Azure go-sdk Client +type AzureClient struct { + agentpools containerservice.AgentPoolsClient +} + +var _ Client = &AzureClient{} + +// NewClient creates a new agent pools client from subscription ID. +func NewClient(subscriptionID string, authorizer autorest.Authorizer) *AzureClient { + c := newAgentPoolsClient(subscriptionID, authorizer) + return &AzureClient{c} +} + +// newAgentPoolsClient creates a new agent pool client from subscription ID. +func newAgentPoolsClient(subscriptionID string, authorizer autorest.Authorizer) containerservice.AgentPoolsClient { + agentPoolsClient := containerservice.NewAgentPoolsClient(subscriptionID) + agentPoolsClient.Authorizer = authorizer + agentPoolsClient.AddToUserAgent(azure.UserAgent) + return agentPoolsClient +} + +// Get gets a agent pool. +func (ac *AzureClient) Get(ctx context.Context, resourceGroupName, cluster, name string) (containerservice.AgentPool, error) { + return ac.agentpools.Get(ctx, resourceGroupName, cluster, name) +} + +// CreateOrUpdate creates or updates a agent pool. +func (ac *AzureClient) CreateOrUpdate(ctx context.Context, resourceGroupName, cluster, name string, properties containerservice.AgentPool) error { + future, err := ac.agentpools.CreateOrUpdate(ctx, resourceGroupName, cluster, name, properties) + if err != nil { + return err + } + err = future.WaitForCompletionRef(ctx, ac.agentpools.Client) + if err != nil { + return err + } + _, err = future.Result(ac.agentpools) + return err +} + +// Delete deletes a agent pool. +func (ac *AzureClient) Delete(ctx context.Context, resourceGroupName, cluster, name string) error { + future, err := ac.agentpools.Delete(ctx, resourceGroupName, cluster, name) + if err != nil { + return err + } + err = future.WaitForCompletionRef(ctx, ac.agentpools.Client) + if err != nil { + return err + } + _, err = future.Result(ac.agentpools) + return err +} diff --git a/cloud/services/agentpools/service.go b/cloud/services/agentpools/service.go new file mode 100644 index 000000000000..496b3eb1ca10 --- /dev/null +++ b/cloud/services/agentpools/service.go @@ -0,0 +1,33 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package agentpools + +import ( + "github.com/Azure/go-autorest/autorest" +) + +// Service provides operations on azure resources +type Service struct { + Client +} + +// NewService creates a new service. +func NewService(authorizer autorest.Authorizer, subscriptionID string) *Service { + return &Service{ + Client: NewClient(subscriptionID, authorizer), + } +} diff --git a/cloud/services/managedclusters/client.go b/cloud/services/managedclusters/client.go new file mode 100644 index 000000000000..809c528882ef --- /dev/null +++ b/cloud/services/managedclusters/client.go @@ -0,0 +1,102 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package managedclusters + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice" + "github.com/Azure/go-autorest/autorest" + "github.com/pkg/errors" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" +) + +// Client wraps go-sdk +type Client interface { + Get(context.Context, string, string) (containerservice.ManagedCluster, error) + GetCredentials(context.Context, string, string) ([]byte, error) + CreateOrUpdate(context.Context, string, string, containerservice.ManagedCluster) error + Delete(context.Context, string, string) error +} + +// AzureClient contains the Azure go-sdk Client +type AzureClient struct { + managedclusters containerservice.ManagedClustersClient +} + +var _ Client = &AzureClient{} + +// NewClient creates a new VM client from subscription ID. +func NewClient(subscriptionID string, authorizer autorest.Authorizer) *AzureClient { + c := newManagedClustersClient(subscriptionID, authorizer) + return &AzureClient{c} +} + +// newManagedClustersClient creates a new managed clusters client from subscription ID. +func newManagedClustersClient(subscriptionID string, authorizer autorest.Authorizer) containerservice.ManagedClustersClient { + managedClustersClient := containerservice.NewManagedClustersClient(subscriptionID) + managedClustersClient.Authorizer = authorizer + managedClustersClient.AddToUserAgent(azure.UserAgent) + return managedClustersClient +} + +// Get gets a managed cluster. +func (ac *AzureClient) Get(ctx context.Context, resourceGroupName, name string) (containerservice.ManagedCluster, error) { + return ac.managedclusters.Get(ctx, resourceGroupName, name) +} + +// GetCredentials fetches the admin kubeconfig for a managed cluster. +func (ac *AzureClient) GetCredentials(ctx context.Context, resourceGroupName, name string) ([]byte, error) { + credentialList, err := ac.managedclusters.ListClusterAdminCredentials(ctx, resourceGroupName, name) + if err != nil { + return nil, err + } + + if credentialList.Kubeconfigs == nil || len(*credentialList.Kubeconfigs) < 1 { + return nil, errors.New("no kubeconfigs available for the managed cluster cluster") + } + + return *(*credentialList.Kubeconfigs)[0].Value, nil +} + +// CreateOrUpdate creates or updates a managed cluster. +func (ac *AzureClient) CreateOrUpdate(ctx context.Context, resourceGroupName, name string, cluster containerservice.ManagedCluster) error { + future, err := ac.managedclusters.CreateOrUpdate(ctx, resourceGroupName, name, cluster) + if err != nil { + return err + } + err = future.WaitForCompletionRef(ctx, ac.managedclusters.Client) + if err != nil { + return err + } + _, err = future.Result(ac.managedclusters) + return err +} + +// Delete deletes a managed cluster. +func (ac *AzureClient) Delete(ctx context.Context, resourceGroupName, name string) error { + future, err := ac.managedclusters.Delete(ctx, resourceGroupName, name) + if err != nil { + return err + } + err = future.WaitForCompletionRef(ctx, ac.managedclusters.Client) + if err != nil { + return err + } + _, err = future.Result(ac.managedclusters) + return err +} diff --git a/cloud/services/managedclusters/managedclusters.go b/cloud/services/managedclusters/managedclusters.go new file mode 100644 index 000000000000..7574e97e53ab --- /dev/null +++ b/cloud/services/managedclusters/managedclusters.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package managedclusters + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice" + "github.com/Azure/go-autorest/autorest/azure/auth" + "github.com/pkg/errors" + "k8s.io/klog" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" +) + +var defaultUser string = "azureuser" + +// Spec contains properties to create a managed cluster. +type Spec struct { + // Name is the name of this AKS Cluster. + Name string + + // ResourceGroup is the name of the Azure resource group for this AKS Cluster. + ResourceGroup string + + // Location is a string matching one of the canonical Azure region names. Examples: "westus2", "eastus". + Location string + + // Tags is a set of tags to add to this cluster. + // +optional + Tags map[string]string + + // Version defines the desired Kubernetes version. + Version string + + // LoadBalancerSKU for the managed cluster. Possible values include: 'Standard', 'Basic'. Defaults to standard. + LoadBalancerSKU *string + + // NetworkPlugin used for building Kubernetes network. Possible values include: 'Azure', 'Kubenet'. Defaults to Azure. + NetworkPlugin *string + + // NetworkPolicy used for building Kubernetes network. Possible values include: 'NetworkPolicyCalico', 'NetworkPolicyAzure'. Defaults to Azure. + NetworkPolicy *string + + // SSHPublicKey is a string literal containing an ssh public key. Will autogenerate and discard if not provided. + SSHPublicKey string + + // AgentPools is the list of agent pool specifications in this cluster. + AgentPools []PoolSpec +} + +type PoolSpec struct { + Name string + SKU string + Replicas int32 + OSDiskSizeGB int32 +} + +// Get fetches a managed cluster from Azure. +func (s *Service) Get(ctx context.Context, spec interface{}) (interface{}, error) { + managedClusterSpec, ok := spec.(*Spec) + if !ok { + return containerservice.ManagedCluster{}, errors.New("expected managed cluster specification") + } + return s.Client.Get(ctx, managedClusterSpec.ResourceGroup, managedClusterSpec.Name) +} + +// Get fetches a managed cluster kubeconfig from Azure. +func (s *Service) GetCredentials(ctx context.Context, spec interface{}) ([]byte, error) { + managedClusterSpec, ok := spec.(*Spec) + if !ok { + return nil, errors.New("expected managed cluster specification") + } + return s.Client.GetCredentials(ctx, managedClusterSpec.ResourceGroup, managedClusterSpec.Name) +} + +// Reconcile idempotently creates or updates a managed cluster, if possible. +func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { + managedClusterSpec, ok := spec.(*Spec) + if !ok { + return errors.New("expected managed cluster specification") + } + + // ****WARNING**** + // ****WARNING**** + // TODO(ace): probably don't do this. + settings, err := auth.GetSettingsFromEnvironment() + if err != nil { + return fmt.Errorf("failed to parse azure environment settings: %v", err) + } + aadClientID, aadClientSecret := settings.Values[auth.ClientID], settings.Values[auth.ClientSecret] + + properties := containerservice.ManagedCluster{ + Location: &managedClusterSpec.Location, + ManagedClusterProperties: &containerservice.ManagedClusterProperties{ + DNSPrefix: &managedClusterSpec.Name, + KubernetesVersion: &managedClusterSpec.Version, + LinuxProfile: &containerservice.LinuxProfile{ + AdminUsername: &defaultUser, + SSH: &containerservice.SSHConfiguration{ + PublicKeys: &[]containerservice.SSHPublicKey{ + { + KeyData: &managedClusterSpec.SSHPublicKey, + }, + }, + }, + }, + ServicePrincipalProfile: &containerservice.ManagedClusterServicePrincipalProfile{ + ClientID: &aadClientID, + Secret: &aadClientSecret, + }, + AgentPoolProfiles: &[]containerservice.ManagedClusterAgentPoolProfile{}, + NetworkProfile: &containerservice.NetworkProfileType{ + NetworkPlugin: containerservice.Azure, + LoadBalancerSku: containerservice.Standard, + }, + }, + } + + if managedClusterSpec.NetworkPlugin != nil { + properties.NetworkProfile.NetworkPlugin = containerservice.NetworkPlugin(*managedClusterSpec.NetworkPlugin) + } + + if managedClusterSpec.NetworkPolicy != nil { + properties.NetworkProfile.NetworkPolicy = containerservice.NetworkPolicy(*managedClusterSpec.NetworkPolicy) + } + + if managedClusterSpec.LoadBalancerSKU != nil { + properties.NetworkProfile.LoadBalancerSku = containerservice.LoadBalancerSku(*managedClusterSpec.LoadBalancerSKU) + } + + for _, pool := range managedClusterSpec.AgentPools { + profile := containerservice.ManagedClusterAgentPoolProfile{ + Name: &pool.Name, + VMSize: containerservice.VMSizeTypes(pool.SKU), + OsDiskSizeGB: &pool.OSDiskSizeGB, + Count: &pool.Replicas, + Type: containerservice.VirtualMachineScaleSets, + } + *properties.AgentPoolProfiles = append(*properties.AgentPoolProfiles, profile) + } + + err = s.Client.CreateOrUpdate(ctx, managedClusterSpec.ResourceGroup, managedClusterSpec.Name, properties) + if err != nil { + return fmt.Errorf("failed to create or update managed cluster, %v", err) + } + + return nil +} + +// Delete deletes the virtual network with the provided name. +func (s *Service) Delete(ctx context.Context, spec interface{}) error { + managedClusterSpec, ok := spec.(*Spec) + if !ok { + return errors.New("expected managed cluster specification") + } + + klog.V(2).Infof("deleting managed cluster %s ", managedClusterSpec.Name) + err := s.Client.Delete(ctx, managedClusterSpec.ResourceGroup, managedClusterSpec.Name) + if err != nil && azure.ResourceNotFound(err) { + // already deleted + return nil + } + if err != nil { + return errors.Wrapf(err, "failed to delete managed cluster %s in resource group %s", managedClusterSpec.Name, managedClusterSpec.ResourceGroup) + } + + klog.V(2).Infof("successfully deleted managed cluster %s ", managedClusterSpec.Name) + return nil +} diff --git a/cloud/services/managedclusters/service.go b/cloud/services/managedclusters/service.go new file mode 100644 index 000000000000..a188fab24b4d --- /dev/null +++ b/cloud/services/managedclusters/service.go @@ -0,0 +1,33 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package managedclusters + +import ( + "github.com/Azure/go-autorest/autorest" +) + +// Service provides operations on azure resources +type Service struct { + Client +} + +// NewService creates a new service. +func NewService(authorizer autorest.Authorizer, subscriptionID string) *Service { + return &Service{ + Client: NewClient(subscriptionID, authorizer), + } +} diff --git a/cloud/services/scalesets/client.go b/cloud/services/scalesets/client.go new file mode 100644 index 000000000000..aa82dfe73ec0 --- /dev/null +++ b/cloud/services/scalesets/client.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scalesets + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" + "github.com/Azure/go-autorest/autorest" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" +) + +// Client wraps go-sdk +type Client interface { + List(context.Context, string) ([]interface{}, error) +} + +// AzureClient contains the Azure go-sdk Client +type AzureClient struct { + scalesets compute.VirtualMachineScaleSetsClient +} + +var _ Client = &AzureClient{} + +// NewClient creates a new VMSS client from subscription ID. +func NewClient(subscriptionID string, authorizer autorest.Authorizer) *AzureClient { + c := newVirtualMachineScaleSetsClient(subscriptionID, authorizer) + return &AzureClient{c} +} + +// newVirtualMachineScaleSetsClient creates a new vmss client from subscription ID. +func newVirtualMachineScaleSetsClient(subscriptionID string, authorizer autorest.Authorizer) compute.VirtualMachineScaleSetsClient { + scaleSetsClient := compute.NewVirtualMachineScaleSetsClient(subscriptionID) + scaleSetsClient.Authorizer = authorizer + scaleSetsClient.AddToUserAgent(azure.UserAgent) + return scaleSetsClient +} + +// Lists all scale sets in a resource group. +func (ac *AzureClient) List(ctx context.Context, resourceGroupName string) ([]interface{}, error) { + itr, err := ac.scalesets.ListComplete(ctx, resourceGroupName) + var instances []interface{} + for ; itr.NotDone(); err = itr.NextWithContext(ctx) { + if err != nil { + return nil, fmt.Errorf("failed to iterate vm scale sets [%w]", err) + } + instances = append(instances, itr.Value()) + } + return instances, nil +} diff --git a/cloud/services/scalesets/service.go b/cloud/services/scalesets/service.go new file mode 100644 index 000000000000..68eaae1500f5 --- /dev/null +++ b/cloud/services/scalesets/service.go @@ -0,0 +1,31 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scalesets + +import "github.com/Azure/go-autorest/autorest" + +// Service provides operations on azure resources +type Service struct { + Client +} + +// NewService creates a new service. +func NewService(authorizer autorest.Authorizer, subscriptionID string) *Service { + return &Service{ + Client: NewClient(subscriptionID, authorizer), + } +} diff --git a/cloud/services/scalesets/vmss.go b/cloud/services/scalesets/vmss.go new file mode 100644 index 000000000000..d2f6674bc76a --- /dev/null +++ b/cloud/services/scalesets/vmss.go @@ -0,0 +1,36 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scalesets + +import ( + "context" + "errors" +) + +// Spec contains properties to identify VMSS in a resource group. +type Spec struct { + ResourceGroup string +} + +// Listreturns a list of provider IDs for the given VM scale set. +func (s *Service) List(ctx context.Context, spec interface{}) ([]interface{}, error) { + scaleSetsSpec, ok := spec.(*Spec) + if !ok { + return nil, errors.New("expected scale set specification") + } + return s.Client.List(ctx, scaleSetsSpec.ResourceGroup) +} diff --git a/cloud/services/scalesetvms/client.go b/cloud/services/scalesetvms/client.go new file mode 100644 index 000000000000..f572017a7573 --- /dev/null +++ b/cloud/services/scalesetvms/client.go @@ -0,0 +1,66 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scalesetvms + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" + "github.com/Azure/go-autorest/autorest" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" +) + +// Client wraps go-sdk +type Client interface { + ListInstances(context.Context, string, string) ([]string, error) +} + +// AzureClient contains the Azure go-sdk Client +type AzureClient struct { + scalesetvms compute.VirtualMachineScaleSetVMsClient +} + +var _ Client = &AzureClient{} + +// NewClient creates a new VMSS client from subscription ID. +func NewClient(subscriptionID string, authorizer autorest.Authorizer) *AzureClient { + c := newVirtualMachineScaleSetVMsClient(subscriptionID, authorizer) + return &AzureClient{c} +} + +// newVirtualMachineScaleSetVMsClient creates a new vmss client from subscription ID. +func newVirtualMachineScaleSetVMsClient(subscriptionID string, authorizer autorest.Authorizer) compute.VirtualMachineScaleSetVMsClient { + scaleSetVMsClient := compute.NewVirtualMachineScaleSetVMsClient(subscriptionID) + scaleSetVMsClient.Authorizer = authorizer + scaleSetVMsClient.AddToUserAgent(azure.UserAgent) + return scaleSetVMsClient +} + +// Lists all instance IDs in a VM scale set. +func (ac *AzureClient) ListInstances(ctx context.Context, resourceGroupName, name string) ([]string, error) { + itr, err := ac.scalesetvms.ListComplete(ctx, resourceGroupName, name, "", "", "") + var instances []string + for ; itr.NotDone(); err = itr.NextWithContext(ctx) { + if err != nil { + return nil, fmt.Errorf("failed to iterate vm scale sets [%w]", err) + } + vm := itr.Value() + instances = append(instances, fmt.Sprintf("azure://%s", *vm.ID)) + } + return instances, nil +} diff --git a/cloud/services/scalesetvms/service.go b/cloud/services/scalesetvms/service.go new file mode 100644 index 000000000000..8414b5e154c9 --- /dev/null +++ b/cloud/services/scalesetvms/service.go @@ -0,0 +1,31 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scalesetvms + +import "github.com/Azure/go-autorest/autorest" + +// Service provides operations on azure resources +type Service struct { + Client +} + +// NewService creates a new service. +func NewService(authorizer autorest.Authorizer, subscriptionID string) *Service { + return &Service{ + Client: NewClient(subscriptionID, authorizer), + } +} diff --git a/cloud/services/scalesetvms/vmss.go b/cloud/services/scalesetvms/vmss.go new file mode 100644 index 000000000000..bbd9a1808364 --- /dev/null +++ b/cloud/services/scalesetvms/vmss.go @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scalesetvms + +import ( + "context" + "errors" +) + +// Spec contains properties to create a managed cluster. +type Spec struct { + Name string + ResourceGroup string +} + +// ListInstances returns a list of provider IDs for the given VM scale set. +func (s *Service) ListInstances(ctx context.Context, spec interface{}) ([]string, error) { + scaleSetVMsSpec, ok := spec.(*Spec) + if !ok { + return nil, errors.New("expected scale set vms specification") + } + return s.Client.ListInstances(ctx, scaleSetVMsSpec.ResourceGroup, scaleSetVMsSpec.Name) +} diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedclusters.yaml new file mode 100644 index 000000000000..0ed43ac0641e --- /dev/null +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedclusters.yaml @@ -0,0 +1,138 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.6 + creationTimestamp: null + name: azuremanagedclusters.infrastructure.cluster.x-k8s.io +spec: + group: infrastructure.cluster.x-k8s.io + names: + categories: + - cluster-api + kind: AzureManagedCluster + listKind: AzureManagedClusterList + plural: azuremanagedclusters + shortNames: + - amc + singular: azuremanagedcluster + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + description: AzureManagedCluster is the Schema for the azuremanagedclusters + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AzureManagedClusterSpec defines the desired state of AzureManagedCluster + properties: + additionalTags: + additionalProperties: + type: string + description: AdditionalTags is an optional set of tags to add to Azure + resources managed by the Azure provider, in addition to the ones + added by default. + type: object + controlPlaneEndpoint: + description: ControlPlaneEndpoint represents the endpoint used to + communicate with the control plane. + properties: + host: + description: The hostname on which the API server is serving. + type: string + port: + description: The port on which the API server is serving. + format: int32 + type: integer + required: + - host + - port + type: object + defaultPoolRef: + description: 'DefaultPoolRef is the specification for the default + pool, without which an AKS cluster cannot be created. TODO(ace): + consider defaulting and making optional pointer?' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + loadBalancerSku: + description: 'LoadBalancerSKU for the managed cluster. Possible values + include: ''Standard'', ''Basic''. Defaults to standard.' + enum: + - Standard + - Basic + type: string + location: + description: 'Location is a string matching one of the canonical Azure + region names. Examples: "westus2", "eastus".' + type: string + networkPlugin: + description: 'NetworkPlugin used for building Kubernetes network. + Possible values include: ''Azure'', ''Kubenet''. Defaults to Azure.' + enum: + - Azure + - Kubenet + type: string + networkPolicy: + description: 'NetworkPolicy used for building Kubernetes network. + Possible values include: ''NetworkPolicyCalico'', ''NetworkPolicyAzure''' + enum: + - NetworkPolicyCalico + - NetworkPolicyAzure + type: string + resourceGroup: + description: ResourceGroup is the name of the Azure resource group + for this AKS Cluster. + type: string + sshPublicKey: + description: SSHPublicKey is a string literal containing an ssh public + key. + type: string + version: + description: Version defines the desired Kubernetes version. + minLength: 2 + pattern: ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)([-0-9a-zA-Z_\.+]*)?$ + type: string + required: + - defaultPoolRef + - location + - resourceGroup + - sshPublicKey + - version + type: object + status: + description: AzureManagedClusterStatus defines the observed state of AzureManagedCluster + properties: + ready: + description: Ready is true when the provider resource is ready. + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml new file mode 100644 index 000000000000..f987a149698c --- /dev/null +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml @@ -0,0 +1,95 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.6 + creationTimestamp: null + name: azuremanagedmachinepools.infrastructure.cluster.x-k8s.io +spec: + group: infrastructure.cluster.x-k8s.io + names: + categories: + - cluster-api + kind: AzureManagedMachinePool + listKind: AzureManagedMachinePoolList + plural: azuremanagedmachinepools + shortNames: + - ammp + singular: azuremanagedmachinepool + scope: Namespaced + versions: + - name: v1alpha3 + schema: + openAPIV3Schema: + description: AzureManagedMachinePool is the Schema for the azuremanagedmachinepools + API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AzureManagedMachinePoolSpec defines the desired state of + AzureManagedMachinePool + properties: + osDiskSizeGB: + description: OSDiskSizeGB is the disk size for every machine in this + master/agent pool. If you specify 0, it will apply the default osDisk + size according to the vmSize specified. + format: int32 + type: integer + providerIDList: + description: ProviderIDList is the unique identifier as specified + by the cloud provider. + items: + type: string + type: array + sku: + description: SKU is the size of the VMs in the node pool. + type: string + required: + - sku + type: object + status: + description: AzureManagedMachinePoolStatus defines the observed state + of AzureManagedMachinePool + properties: + errorMessage: + description: Any transient errors that occur during the reconciliation + of Machines can be added as events to the Machine object and/or + logged in the controller's output. + type: string + errorReason: + description: Any transient errors that occur during the reconciliation + of Machines can be added as events to the Machine object and/or + logged in the controller's output. + type: string + ready: + description: Ready is true when the provider resource is ready. + type: boolean + replicas: + description: Replicas is the most recently observed number of replicas. + format: int32 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 214dd10da505..fb62ec0effed 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -8,14 +8,19 @@ resources: - bases/infrastructure.cluster.x-k8s.io_azuremachines.yaml - bases/infrastructure.cluster.x-k8s.io_azureclusters.yaml - bases/infrastructure.cluster.x-k8s.io_azuremachinetemplates.yaml + - bases/infrastructure.cluster.x-k8s.io_azuremanagedmachinepools.yaml + - bases/infrastructure.cluster.x-k8s.io_azuremanagedclusters.yaml # +kubebuilder:scaffold:crdkustomizeresource + patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD - patches/webhook_in_azuremachines.yaml - patches/webhook_in_azureclusters.yaml - patches/webhook_in_azuremachinetemplates.yaml + # - patches/webhook_in_azuremanagedmachinepools.yaml + # - patches/webhook_in_azuremanagedclusters.yaml # +kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. @@ -23,6 +28,8 @@ patchesStrategicMerge: - patches/cainjection_in_azuremachines.yaml - patches/cainjection_in_azureclusters.yaml - patches/cainjection_in_azuremachinetemplates.yaml + # - patches/cainjection_in_azuremanagedmachinepools.yaml + # - patches/cainjection_in_azuremanagedclusters.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_azuremanagedclusters.yaml b/config/crd/patches/cainjection_in_azuremanagedclusters.yaml new file mode 100644 index 000000000000..8a7eb5765930 --- /dev/null +++ b/config/crd/patches/cainjection_in_azuremanagedclusters.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: azuremanagedclusters.infrastructure.cluster.x-k8s.io diff --git a/config/crd/patches/cainjection_in_azuremanagedmachinepools.yaml b/config/crd/patches/cainjection_in_azuremanagedmachinepools.yaml new file mode 100644 index 000000000000..dc9610ffc739 --- /dev/null +++ b/config/crd/patches/cainjection_in_azuremanagedmachinepools.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: azuremanagedmachinepools.infrastructure.cluster.x-k8s.io diff --git a/config/crd/patches/webhook_in_azuremanagedclusters.yaml b/config/crd/patches/webhook_in_azuremanagedclusters.yaml new file mode 100644 index 000000000000..8bdb4c52ee48 --- /dev/null +++ b/config/crd/patches/webhook_in_azuremanagedclusters.yaml @@ -0,0 +1,19 @@ +# The following patch enables conversion webhook for CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: azuremanagedclusters.infrastructure.cluster.x-k8s.io +spec: + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert \ No newline at end of file diff --git a/config/crd/patches/webhook_in_azuremanagedmachinepools.yaml b/config/crd/patches/webhook_in_azuremanagedmachinepools.yaml new file mode 100644 index 000000000000..ee0dca7d9e54 --- /dev/null +++ b/config/crd/patches/webhook_in_azuremanagedmachinepools.yaml @@ -0,0 +1,19 @@ +# The following patch enables conversion webhook for CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: azuremanagedmachinepools.infrastructure.cluster.x-k8s.io +spec: + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1", "v1beta1"] + clientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert \ No newline at end of file diff --git a/config/manager/manager_image_patch.yaml b/config/manager/manager_image_patch.yaml index 0876a1db40db..97b19f11c52a 100644 --- a/config/manager/manager_image_patch.yaml +++ b/config/manager/manager_image_patch.yaml @@ -8,5 +8,5 @@ spec: spec: containers: # Change the value of image field below to your controller image URL - - image: gcr.io/k8s-staging-cluster-api-azure/cluster-api-azure-controller:latest + - image: docker.io/alexeldeib/cluster-api-azure-controller:latest name: manager diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 97c8d491a93b..0a3db520da88 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -22,8 +22,10 @@ rules: resources: - secrets verbs: + - create - get - list + - patch - watch - apiGroups: - cluster.x-k8s.io @@ -33,6 +35,7 @@ rules: verbs: - get - list + - patch - watch - apiGroups: - cluster.x-k8s.io @@ -43,6 +46,15 @@ rules: - get - list - watch +- apiGroups: + - exp.cluster.x-k8s.io + resources: + - machinepools + - machinepools/status + verbs: + - get + - list + - watch - apiGroups: - infrastructure.cluster.x-k8s.io resources: @@ -83,3 +95,43 @@ rules: - get - patch - update +- apiGroups: + - infrastructure.cluster.x-k8s.io + resources: + - azuremanagedclusters + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - infrastructure.cluster.x-k8s.io + resources: + - azuremanagedclusters/status + verbs: + - get + - patch + - update +- apiGroups: + - infrastructure.cluster.x-k8s.io + resources: + - azuremanagedmachinepools + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - infrastructure.cluster.x-k8s.io + resources: + - azuremanagedmachinepools/status + verbs: + - get + - patch + - update diff --git a/controllers/azurecluster_controller.go b/controllers/azurecluster_controller.go index d14ce28ae200..fe4f4395a12f 100644 --- a/controllers/azurecluster_controller.go +++ b/controllers/azurecluster_controller.go @@ -52,6 +52,7 @@ func (r *AzureClusterReconciler) SetupWithManager(mgr ctrl.Manager, options cont // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureclusters,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureclusters/status,verbs=get;update;patch // +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;patch func (r *AzureClusterReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr error) { ctx := context.TODO() diff --git a/controllers/azuremanagedcluster_controller.go b/controllers/azuremanagedcluster_controller.go new file mode 100644 index 000000000000..f828d36034d8 --- /dev/null +++ b/controllers/azuremanagedcluster_controller.go @@ -0,0 +1,207 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "os" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure/auth" + "github.com/go-logr/logr" + "github.com/pkg/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/client-go/tools/record" + infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3" + + "sigs.k8s.io/cluster-api/util" + "sigs.k8s.io/cluster-api/util/patch" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// TODO(ace): put this back in the scope package +type ManagedClusterContext struct { + log logr.Logger + patchhelper *patch.Helper + aksCluster *infrav1.AzureManagedCluster + ownerCluster *clusterv1.Cluster + infraPool *infrav1.AzureManagedMachinePool + ownerPool *expv1.MachinePool +} + +// AzureManagedClusterReconciler reconciles a AzureManagedCluster object +type AzureManagedClusterReconciler struct { + client.Client + Log logr.Logger + Recorder record.EventRecorder +} + +func (r *AzureManagedClusterReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { + return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&infrav1.AzureManagedCluster{}). + Complete(r) +} + +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch + +func (r *AzureManagedClusterReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx := context.TODO() + log := r.Log.WithValues("namespace", req.Namespace, "aksCluster", req.Name) + + // Fetch the AzureManagedCluster instance + aksCluster := &infrav1.AzureManagedCluster{} + err := r.Get(ctx, req.NamespacedName, aksCluster) + if err != nil { + if apierrors.IsNotFound(err) { + return reconcile.Result{}, nil + } + return reconcile.Result{}, err + } + + // Fetch the Cluster. + cluster, err := util.GetOwnerCluster(ctx, r.Client, aksCluster.ObjectMeta) + if err != nil { + return reconcile.Result{}, err + } + if cluster == nil { + log.Info("Cluster Controller has not yet set OwnerRef") + return reconcile.Result{}, nil + } + + log = log.WithValues("cluster", cluster.Name) + + // initialize patch helper + patchhelper, err := patch.NewHelper(aksCluster, r.Client) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to init patchhelper") + } + + // Always close the scope when exiting this function so we can persist any changes. + defer func() { + if err := patchhelper.Patch(ctx, aksCluster); err != nil && reterr == nil { + reterr = err + } + }() + + // extract subscription ID from environment + // TODO(ace): don't do this here + subscriptionID := os.Getenv("AZURE_SUBSCRIPTION_ID") + if subscriptionID == "" { + return reconcile.Result{}, errors.New("error creating azure services. Environment variable AZURE_SUBSCRIPTION_ID is not set") + } + + // fetch azure authorizer + // TODO(ace): probably use a secret ref/object ref instead? + authorizer, err := auth.NewAuthorizerFromEnvironment() + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to get authorizer from environment") + } + + // fetch default pool + defaultPoolKey := client.ObjectKey{ + Name: aksCluster.Spec.DefaultPoolRef.Name, + Namespace: aksCluster.ObjectMeta.Namespace, + } + defaultPool := &infrav1.AzureManagedMachinePool{} + if err := r.Client.Get(ctx, defaultPoolKey, defaultPool); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "failed to fetch default pool reference") + } + + // fetch owner of default pool + // TODO(ace): create a helper in util for this + // Fetch the owning MachinePool. + ownerPool, err := getOwnerMachinePool(ctx, r.Client, defaultPool.ObjectMeta) + if err != nil { + return reconcile.Result{}, err + } + if ownerPool == nil { + log.Info("failed to fetch owner ref for default pool") + return reconcile.Result{}, nil + } + + // TODO(ace): move to scope + scope := &ManagedClusterContext{ + log: log, + patchhelper: patchhelper, + aksCluster: aksCluster, + ownerCluster: cluster, + infraPool: defaultPool, + ownerPool: ownerPool, + } + + // Handle deleted clusters + if !aksCluster.DeletionTimestamp.IsZero() { + return r.reconcileDelete(ctx, scope, subscriptionID, authorizer) + } + + // Handle non-deleted clusters + return r.reconcileNormal(ctx, scope, subscriptionID, authorizer) +} + +func (r *AzureManagedClusterReconciler) reconcileNormal(ctx context.Context, scope *ManagedClusterContext, subscriptionID string, authorizer autorest.Authorizer) (reconcile.Result, error) { + scope.log.Info("Reconciling AzureManagedCluster") + + // If the AzureManagedCluster doesn't have our finalizer, add it. + controllerutil.AddFinalizer(scope.aksCluster, infrav1.ClusterFinalizer) + // Register the finalizer immediately to avoid orphaning Azure resources on delete + if err := scope.patchhelper.Patch(ctx, scope.aksCluster); err != nil { + return reconcile.Result{}, err + } + + if err := newAzureManagedClusterReconciler(subscriptionID, authorizer, r.Client).Reconcile(ctx, scope); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "error creating AzureManagedCluster %s/%s", scope.aksCluster.Namespace, scope.aksCluster.Name) + } + + // No errors, so mark us ready so the Cluster API Cluster Controller can pull it + scope.aksCluster.Status.Ready = true + scope.ownerCluster.Status.ControlPlaneInitialized = true + scope.ownerCluster.Status.ControlPlaneReady = true + + if err := scope.patchhelper.Patch(ctx, scope.aksCluster); err != nil { + return reconcile.Result{}, err + } + + if err := scope.patchhelper.Patch(ctx, scope.ownerCluster); err != nil { + return reconcile.Result{}, err + } + + scope.log.Info("Successfully reconciled") + + return reconcile.Result{}, nil +} + +func (r *AzureManagedClusterReconciler) reconcileDelete(ctx context.Context, scope *ManagedClusterContext, subscriptionID string, authorizer autorest.Authorizer) (reconcile.Result, error) { + scope.log.Info("Reconciling AzureManagedCluster delete") + + if err := newAzureManagedClusterReconciler(subscriptionID, authorizer, r.Client).Delete(ctx, scope); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "error deleting AzureManagedCluster %s/%s", scope.aksCluster.Namespace, scope.aksCluster.Name) + } + + // Cluster is deleted so remove the finalizer. + controllerutil.RemoveFinalizer(scope.aksCluster, infrav1.ClusterFinalizer) + + return reconcile.Result{}, nil +} diff --git a/controllers/azuremanagedcluster_reconciler.go b/controllers/azuremanagedcluster_reconciler.go new file mode 100644 index 000000000000..919788975cae --- /dev/null +++ b/controllers/azuremanagedcluster_reconciler.go @@ -0,0 +1,158 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice" + "github.com/Azure/go-autorest/autorest" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" + "sigs.k8s.io/cluster-api-provider-azure/cloud/services/managedclusters" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + "sigs.k8s.io/cluster-api/util/secret" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// azureManagedClusterReconciler are list of services required by cluster controller +type azureManagedClusterReconciler struct { + kubeclient client.Client + managedClustersSvc azure.CredentialGetter +} + +// newAzureManagedClusterReconciler populates all the services based on input scope +func newAzureManagedClusterReconciler(subscriptionID string, authorizer autorest.Authorizer, kubeclient client.Client) *azureManagedClusterReconciler { + return &azureManagedClusterReconciler{ + kubeclient: kubeclient, + managedClustersSvc: managedclusters.NewService(authorizer, subscriptionID), + } +} + +// Reconcile reconciles all the services in pre determined order +func (r *azureManagedClusterReconciler) Reconcile(ctx context.Context, scope *ManagedClusterContext) error { + scope.log.Info("reconciling cluster") + managedClusterSpec := &managedclusters.Spec{ + Name: scope.aksCluster.Name, + ResourceGroup: scope.aksCluster.Spec.ResourceGroup, + Location: scope.aksCluster.Spec.Location, + Tags: scope.aksCluster.Spec.AdditionalTags, + Version: scope.aksCluster.Spec.Version, + LoadBalancerSKU: scope.aksCluster.Spec.LoadBalancerSKU, + NetworkPlugin: scope.aksCluster.Spec.NetworkPlugin, + NetworkPolicy: scope.aksCluster.Spec.NetworkPolicy, + SSHPublicKey: scope.aksCluster.Spec.SSHPublicKey, + } + + _, err := r.managedClustersSvc.Get(ctx, managedClusterSpec) + if err != nil && !azure.ResourceNotFound(err) { + return errors.Wrapf(err, "failed to reconcile managed cluster %s", scope.aksCluster.Name) + } + + // Configure the default pool, rest will be handled by machinepool controller + defaultPoolSpec := managedclusters.PoolSpec{ + Name: scope.infraPool.Name, + SKU: scope.infraPool.Spec.SKU, + Replicas: 1, + OSDiskSizeGB: 0, + } + + if scope.infraPool.Spec.OSDiskSizeGB != nil { + defaultPoolSpec.OSDiskSizeGB = *scope.infraPool.Spec.OSDiskSizeGB + } + if scope.ownerPool.Spec.Replicas != nil { + defaultPoolSpec.Replicas = *scope.ownerPool.Spec.Replicas + } + + managedClusterSpec.AgentPools = []managedclusters.PoolSpec{defaultPoolSpec} + + if azure.ResourceNotFound(err) { + // We are creating this cluster for the first time. + if err := r.managedClustersSvc.Reconcile(ctx, managedClusterSpec); err != nil { + return errors.Wrapf(err, "failed to reconcile managed cluster %s", scope.aksCluster.Name) + } + scope.log.Info("reconciled managed cluster successfully") + return nil + } + + // Fetched newly created credentials + managedClusterResult, err := r.managedClustersSvc.Get(ctx, managedClusterSpec) + if err != nil { + return err + } + + managedCluster, ok := managedClusterResult.(containerservice.ManagedCluster) + if !ok { + return fmt.Errorf("expected containerservice ManagedCluster object") + } + + scope.aksCluster.Spec.ControlPlaneEndpoint = clusterv1.APIEndpoint{ + Host: *managedCluster.ManagedClusterProperties.Fqdn, + Port: 443, + } + + // Fetched newly created credentials + data, err := r.managedClustersSvc.GetCredentials(ctx, managedClusterSpec) + if err != nil { + return err + } + + // Construct and store secret + kubeconfig := makeKubeconfig(scope.ownerCluster) + _, err = controllerutil.CreateOrUpdate(ctx, r.kubeclient, kubeconfig, func() error { + kubeconfig.Data = map[string][]byte{ + secret.KubeconfigDataName: data, + } + return nil + }) + + // if err != nil { + // scope.log.Error(err) + // } + + return err +} + +// Delete reconciles all the services in pre determined order +func (r *azureManagedClusterReconciler) Delete(ctx context.Context, scope *ManagedClusterContext) error { + if err := r.managedClustersSvc.Delete(ctx, nil); err != nil { + return errors.Wrapf(err, "failed to delete managed cluster %s", scope.aksCluster.Name) + } + + return nil +} + +func makeKubeconfig(cluster *clusterv1.Cluster) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secret.Name(cluster.Name, secret.Kubeconfig), + Namespace: cluster.Namespace, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: clusterv1.GroupVersion.String(), + Kind: "Cluster", + Name: cluster.Name, + UID: cluster.UID, + }, + }, + }, + } +} diff --git a/controllers/azuremanagedmachinepool_controller.go b/controllers/azuremanagedmachinepool_controller.go new file mode 100644 index 000000000000..efa3c041c143 --- /dev/null +++ b/controllers/azuremanagedmachinepool_controller.go @@ -0,0 +1,208 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "os" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure/auth" + "github.com/go-logr/logr" + "github.com/pkg/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/record" + infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3" + expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3" + + "sigs.k8s.io/cluster-api/util" + "sigs.k8s.io/cluster-api/util/patch" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// AzureManagedMachinePoolReconciler reconciles a AzureManagedMachinePool object +type AzureManagedMachinePoolReconciler struct { + client.Client + Log logr.Logger + Recorder record.EventRecorder +} + +func (r *AzureManagedMachinePoolReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { + return ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&infrav1.AzureManagedMachinePool{}). + Complete(r) +} + +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedmachinepools,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azuremanagedmachinepools/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch;patch +// +kubebuilder:rbac:groups=exp.cluster.x-k8s.io,resources=machinepools;machinepools/status,verbs=get;list;watch + +func (r *AzureManagedMachinePoolReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr error) { + ctx := context.TODO() + log := r.Log.WithValues("namespace", req.Namespace, "infraPool", req.Name) + + // Fetch the AzureManagedMachinePool instance + infraPool := &infrav1.AzureManagedMachinePool{} + err := r.Get(ctx, req.NamespacedName, infraPool) + if err != nil { + if apierrors.IsNotFound(err) { + return reconcile.Result{}, nil + } + return reconcile.Result{}, err + } + + // Fetch the owning MachinePool. + ownerPool, err := getOwnerMachinePool(ctx, r.Client, infraPool.ObjectMeta) + if err != nil { + return reconcile.Result{}, err + } + if ownerPool == nil { + log.Info("MachinePool Controller has not yet set OwnerRef") + return reconcile.Result{}, nil + } + + // Fetch the Cluster. + ownerCluster, err := util.GetOwnerCluster(ctx, r.Client, ownerPool.ObjectMeta) + if err != nil { + return reconcile.Result{}, err + } + if ownerCluster == nil { + log.Info("Cluster Controller has not yet set OwnerRef") + return reconcile.Result{}, nil + } + + log = log.WithValues("ownerCluster", ownerCluster.Name) + + // Fetch the managed cluster + infraCluster := &infrav1.AzureManagedCluster{} + infraClusterName := client.ObjectKey{ + Namespace: infraPool.Namespace, + Name: ownerCluster.Spec.InfrastructureRef.Name, + } + if err := r.Client.Get(ctx, infraClusterName, infraCluster); err != nil { + return reconcile.Result{}, err + } + + // initialize patch helper + patchhelper, err := patch.NewHelper(infraPool, r.Client) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to init patchhelper") + } + + // Always close the scope when exiting this function so we can persist any changes. + defer func() { + if err := patchhelper.Patch(ctx, infraPool); err != nil && reterr == nil { + reterr = err + } + }() + + // extract subscription ID from environment + // TODO(ace): don't do this here + subscriptionID := os.Getenv("AZURE_SUBSCRIPTION_ID") + if subscriptionID == "" { + return reconcile.Result{}, errors.New("error creating azure services. Environment variable AZURE_SUBSCRIPTION_ID is not set") + } + + // fetch azure authorizer + // TODO(ace): probably use a secret ref/object ref instead? + authorizer, err := auth.NewAuthorizerFromEnvironment() + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to get authorizer from environment") + } + + // ... + scope := &ManagedClusterContext{ + log: log, + patchhelper: patchhelper, + aksCluster: infraCluster, + infraPool: infraPool, + ownerCluster: ownerCluster, + ownerPool: ownerPool, + } + + // Handle deleted clusters + if !infraPool.DeletionTimestamp.IsZero() { + return r.reconcileDelete(ctx, scope, subscriptionID, authorizer) + } + + // Handle non-deleted clusters + return r.reconcileNormal(ctx, scope, subscriptionID, authorizer) +} + +func (r *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Context, scope *ManagedClusterContext, subscriptionID string, authorizer autorest.Authorizer) (reconcile.Result, error) { + scope.log.Info("Reconciling AzureManagedMachinePool") + + // If the AzureManagedMachinePool doesn't have our finalizer, add it. + controllerutil.AddFinalizer(scope.infraPool, infrav1.ClusterFinalizer) + // Register the finalizer immediately to avoid orphaning Azure resources on delete + if err := scope.patchhelper.Patch(ctx, scope.infraPool); err != nil { + return reconcile.Result{}, err + } + + if err := newAzureManagedMachinePoolReconciler(subscriptionID, authorizer, r.Client).Reconcile(ctx, scope); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "error creating AzureManagedMachinePool %s/%s", scope.infraPool.Namespace, scope.infraPool.Name) + } + + // No errors, so mark us ready so the Cluster API Cluster Controller can pull it + scope.infraPool.Status.Ready = true + + if err := scope.patchhelper.Patch(ctx, scope.infraPool); err != nil { + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} + +func (r *AzureManagedMachinePoolReconciler) reconcileDelete(ctx context.Context, scope *ManagedClusterContext, subscriptionID string, authorizer autorest.Authorizer) (reconcile.Result, error) { + scope.log.Info("Reconciling AzureManagedMachinePool delete") + + if err := newAzureManagedMachinePoolReconciler(subscriptionID, authorizer, r.Client).Delete(ctx, scope); err != nil { + return reconcile.Result{}, errors.Wrapf(err, "error deleting AzureManagedMachinePool %s/%s", scope.infraPool.Namespace, scope.infraPool.Name) + } + + // Cluster is deleted so remove the finalizer. + controllerutil.RemoveFinalizer(scope.infraPool, infrav1.ClusterFinalizer) + + return reconcile.Result{}, nil +} + +// getOwnerMachinePool returns the MachinePool object owning the current resource. +func getOwnerMachinePool(ctx context.Context, c client.Client, obj metav1.ObjectMeta) (*expv1.MachinePool, error) { + for _, ref := range obj.OwnerReferences { + if ref.Kind == "MachinePool" && ref.APIVersion == expv1.GroupVersion.String() { + return getMachinePoolByName(ctx, c, obj.Namespace, ref.Name) + } + } + return nil, nil +} + +// getMachinePoolByName finds and return a MachinePool object using the specified params. +func getMachinePoolByName(ctx context.Context, c client.Client, namespace, name string) (*expv1.MachinePool, error) { + m := &expv1.MachinePool{} + key := client.ObjectKey{Name: name, Namespace: namespace} + if err := c.Get(ctx, key, m); err != nil { + return nil, err + } + return m, nil +} diff --git a/controllers/azuremanagedmachinepool_reconciler.go b/controllers/azuremanagedmachinepool_reconciler.go new file mode 100644 index 000000000000..ca3601773286 --- /dev/null +++ b/controllers/azuremanagedmachinepool_reconciler.go @@ -0,0 +1,138 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" + "github.com/Azure/go-autorest/autorest" + "github.com/pkg/errors" + azure "sigs.k8s.io/cluster-api-provider-azure/cloud" + "sigs.k8s.io/cluster-api-provider-azure/cloud/services/agentpools" + "sigs.k8s.io/cluster-api-provider-azure/cloud/services/scalesets" + "sigs.k8s.io/cluster-api-provider-azure/cloud/services/scalesetvms" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// azureManagedMachinePoolReconciler are list of services required by cluster controller +type azureManagedMachinePoolReconciler struct { + kubeclient client.Client + agentPoolsSvc azure.GetterService + scaleSetVMsSvc NodeLister + scaleSetsSvc Lister +} + +// NodeLister is a service interface exclusively for returning a list of VMSS instance provider IDs. +type NodeLister interface { + ListInstances(context.Context, interface{}) ([]string, error) +} + +// Lister is a service interface for returning generic lists. +type Lister interface { + List(context.Context, interface{}) ([]interface{}, error) +} + +// newAzureManagedMachinePoolReconciler populates all the services based on input scope +func newAzureManagedMachinePoolReconciler(subscriptionID string, authorizer autorest.Authorizer, kubeclient client.Client) *azureManagedMachinePoolReconciler { + return &azureManagedMachinePoolReconciler{ + kubeclient: kubeclient, + agentPoolsSvc: agentpools.NewService(authorizer, subscriptionID), + scaleSetVMsSvc: scalesetvms.NewService(authorizer, subscriptionID), + scaleSetsSvc: scalesets.NewService(authorizer, subscriptionID), + } +} + +// Reconcile reconciles all the services in pre determined order +func (r *azureManagedMachinePoolReconciler) Reconcile(ctx context.Context, scope *ManagedClusterContext) error { + scope.log.Info("reconciling machine pool") + agentPoolSpec := &agentpools.Spec{ + Name: scope.infraPool.Name, + ResourceGroup: scope.aksCluster.Spec.ResourceGroup, + Cluster: scope.aksCluster.Name, + SKU: scope.infraPool.Spec.SKU, + Replicas: 1, + } + + if scope.infraPool.Spec.OSDiskSizeGB != nil { + agentPoolSpec.OSDiskSizeGB = *scope.infraPool.Spec.OSDiskSizeGB + } + + if scope.ownerPool.Spec.Replicas != nil { + agentPoolSpec.Replicas = *scope.ownerPool.Spec.Replicas + } + + if err := r.agentPoolsSvc.Reconcile(ctx, agentPoolSpec); err != nil { + return errors.Wrapf(err, "failed to reconcile machine pool %s", scope.infraPool.Name) + } + + nodeResourceGroup := fmt.Sprintf("MC_%s_%s_%s", scope.aksCluster.Spec.ResourceGroup, scope.aksCluster.Name, scope.aksCluster.Spec.Location) + vmss, err := r.scaleSetsSvc.List(ctx, &scalesets.Spec{ResourceGroup: nodeResourceGroup}) + if err != nil { + return errors.Wrapf(err, "failed to list vmss in resource group %s", nodeResourceGroup) + } + + var match *compute.VirtualMachineScaleSet + for _, ss := range vmss { + ss := ss + switch scaleset := ss.(type) { + case compute.VirtualMachineScaleSet: + if scaleset.Tags["poolName"] != nil && *scaleset.Tags["poolName"] == scope.infraPool.Name { + match = &scaleset + break + } + default: + return errors.New("expected vmss but found wrong interface type") + } + } + + if match == nil { + return errors.New("failed to find vm scale set matchinf pool") + } + + providerIDs, err := r.scaleSetVMsSvc.ListInstances(ctx, &scalesetvms.Spec{ + Name: *match.Name, + ResourceGroup: nodeResourceGroup, + }) + if err != nil { + return errors.Wrapf(err, "failed to reconcile machine pool %s", scope.infraPool.Name) + } + + scope.infraPool.Spec.ProviderIDList = providerIDs + scope.infraPool.Status.Replicas = int32(len(providerIDs)) + scope.infraPool.Status.Ready = true + + scope.log.Info("reconciled machine pool successfully") + return nil +} + +// Delete reconciles all the services in pre determined order +func (r *azureManagedMachinePoolReconciler) Delete(ctx context.Context, scope *ManagedClusterContext) error { + agentPoolSpec := &agentpools.Spec{ + Name: scope.infraPool.Name, + ResourceGroup: scope.aksCluster.Spec.ResourceGroup, + Cluster: scope.aksCluster.Name, + SKU: scope.infraPool.Spec.SKU, + } + + if err := r.agentPoolsSvc.Delete(ctx, agentPoolSpec); err != nil { + return errors.Wrapf(err, "failed to delete machine pool %s", scope.infraPool.Name) + } + + return nil +} diff --git a/go.mod b/go.mod index 38f0e42be394..dbb4603923d3 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/blang/semver v3.5.1+incompatible github.com/go-logr/logr v0.1.0 github.com/golang/mock v1.4.0 + github.com/google/go-cmp v0.4.0 github.com/google/gofuzz v1.1.0 github.com/onsi/ginkgo v1.12.0 github.com/onsi/gomega v1.9.0 diff --git a/go.sum b/go.sum index 2f43b6732760..c361527fb287 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,15 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= github.com/Azure/azure-sdk-for-go v41.0.0+incompatible h1:nQc4CAuBSr8rO0aZ90NvHoKyWYodhtzSAS4DPDrCtqo= github.com/Azure/azure-sdk-for-go v41.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.10.0 h1:mvdtztBqcL8se7MdrUweNieTNi4kfNG6GOJuurQJpuY= github.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0 h1:CxTzQrySOxDnKpLjFJeZAS5Qrv/qFPkgLjx5bOAi//I= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= @@ -24,14 +17,11 @@ github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwp github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U= github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= -github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= @@ -41,43 +31,35 @@ github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1Gn github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053 h1:H/GMMKYPkEIC3DF/JWQz8Pdd+Feifov2EIgGfNpeogI= github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053/go.mod h1:xW8sBma2LE3QxFSzCnH9qe6gAE2yO9GvQaWwX89HxbE= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= -github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/caddyserver/caddy v1.0.3 h1:i9gRhBgvc5ifchwWtSe7pDpsdS9+Q0Rw9oYQmYUTw1w= github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -88,7 +70,6 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coredns/corefile-migration v1.0.7 h1:T2eOj/NKN1Q1W1bD9MFeZiBYryS0JlWT6aROAvVWFSs= github.com/coredns/corefile-migration v1.0.7/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -105,6 +86,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -113,33 +95,25 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -164,13 +138,11 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -193,68 +165,52 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -264,11 +220,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -278,31 +231,24 @@ github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= @@ -310,37 +256,29 @@ github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -353,18 +291,14 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= @@ -372,40 +306,32 @@ github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2i github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.5.0 h1:Ctq0iGpCmr3jeP77kbF2UxgvRwzWWz+4Bh9/vJTyg1A= github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -413,51 +339,39 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -475,13 +389,9 @@ go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -494,9 +404,7 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -526,15 +434,11 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -555,7 +459,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -563,19 +466,15 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -593,13 +492,9 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 h1:bw9doJza/SFBEweII/rHQh338oozWyiFsBRHtrflcws= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -607,7 +502,6 @@ gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmK google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -621,16 +515,13 @@ google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= @@ -640,50 +531,35 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.17.2 h1:NF1UFXcKN7/OOv1uxdRz3qfra8AHsPav5M93hlV9+Dc= k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= -k8s.io/apiextensions-apiserver v0.17.2 h1:cP579D2hSZNuO/rZj9XFRzwJNYb41DbNANJb6Kolpss= k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.17.2 h1:hwDQQFbdRlpnnsR64Asdi55GyCaIP/3WQpMmbNBeWr4= k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apiserver v0.17.2 h1:NssVvPALll6SSeNgo1Wk1h2myU1UHNwmhxV0Oxbcl8Y= k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= -k8s.io/client-go v0.17.2 h1:ndIfkfXEGrNhLIgkr0+qhRguSD3u6DCmonepn1O6NYc= k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= k8s.io/cluster-bootstrap v0.17.2 h1:KVjK1WviylwbBwC+3L51xKmGN3A+WmzW8rhtcfWdUqQ= k8s.io/cluster-bootstrap v0.17.2/go.mod h1:qiazpAM05fjAc+PEkrY8HSUhKlJSMBuLnVUSO6nvZL4= -k8s.io/code-generator v0.17.2 h1:pTwl3rLB1fUyxmvEzmVPMM0tBSdUehd7z+bDzpj4lPE= k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/component-base v0.17.2 h1:0XHf+cerTvL9I5Xwn9v+0jmqzGAZI7zNydv4tL6Cw6A= k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab h1:I3f2hcBrepGRXI1z4sukzAb8w1R4eqbsHrAsx06LGYM= k8s.io/utils v0.0.0-20200229041039-0a110f9eb7ab/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= @@ -696,12 +572,9 @@ sigs.k8s.io/cluster-api v0.3.3 h1:pNuvC6cm67SbxOaPriK8ZfLl1RSjmu/KX2GJiNQH3dU= sigs.k8s.io/cluster-api v0.3.3/go.mod h1:lgztyeCWCve8YB4DN6QeLR0blNYBvFX9+ATHrxs+zKU= sigs.k8s.io/controller-runtime v0.5.2 h1:pyXbUfoTo+HA3jeIfr0vgi+1WtmNh0CwlcnQGLXwsSw= sigs.k8s.io/controller-runtime v0.5.2/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A= -sigs.k8s.io/kind v0.7.1-0.20200303021537-981bd80d3802 h1:L6/8hETA7jvdx3xBcbDifrIN2xaYHE7tA58n+Kdp2Zw= sigs.k8s.io/kind v0.7.1-0.20200303021537-981bd80d3802/go.mod h1:HIZ3PWUezpklcjkqpFbnYOqaqsAE1JeCTEwkgvPLXjk= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/main.go b/main.go index e9af9fe8929c..182800763d92 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Kubernetes Authors. +Copyright 2020 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. @@ -36,6 +36,7 @@ import ( infrav1alpha3 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3" "sigs.k8s.io/cluster-api-provider-azure/controllers" clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + expv1 "sigs.k8s.io/cluster-api/exp/api/v1alpha3" "sigs.k8s.io/cluster-api/feature" "sigs.k8s.io/cluster-api/util/record" ctrl "sigs.k8s.io/controller-runtime" @@ -56,6 +57,8 @@ func init() { _ = infrav1alpha3.AddToScheme(scheme) _ = clusterv1.AddToScheme(scheme) _ = infrastructurev1alpha3.AddToScheme(scheme) + _ = expv1.AddToScheme(scheme) + // +kubebuilder:scaffold:scheme } @@ -193,6 +196,22 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "AzureCluster") os.Exit(1) } + if err = (&controllers.AzureManagedMachinePoolReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("AzureManagedMachinePool"), + Recorder: mgr.GetEventRecorderFor("azuremachine-reconciler"), + }).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "AzureManagedMachinePool") + os.Exit(1) + } + if err = (&controllers.AzureManagedClusterReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("AzureManagedCluster"), + Recorder: mgr.GetEventRecorderFor("azurecluster-reconciler"), + }).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "AzureManagedCluster") + os.Exit(1) + } } else { if err = (&infrastructurev1alpha3.AzureCluster{}).SetupWebhookWithManager(mgr); err != nil { setupLog.Error(err, "unable to create webhook", "webhook", "AzureCluster")