diff --git a/Makefile b/Makefile index bd5f83a4523..fbc9e34e12c 100644 --- a/Makefile +++ b/Makefile @@ -119,12 +119,17 @@ validate-copyright-headers: # Generate manifests for helm and package them up helm-chart-manifests: manifests - kustomize build ./config/default -o ./charts/azure-service-operator/templates - rm charts/azure-service-operator/templates/~g_v1_namespace_azureoperator-system.yaml - sed -i '' -e 's@controller:latest@{{ .Values.image.repository }}@' ./charts/azure-service-operator/templates/apps_v1_deployment_azureoperator-controller-manager.yaml + mkdir charts/azure-service-operator/templates/generated + kustomize build ./config/default -o ./charts/azure-service-operator/templates/generated + rm charts/azure-service-operator/templates/generated/~g_v1_namespace_azureoperator-system.yaml + sed -i '' -e 's@controller:latest@{{ .Values.image.repository }}@' ./charts/azure-service-operator/templates/generated/apps_v1_deployment_azureoperator-controller-manager.yaml + find ./charts/azure-service-operator/templates/generated/ -type f -exec sed -i '' -e 's@namespace: azureoperator-system@namespace: {{ .Values.namespace }}@' {} \; helm package ./charts/azure-service-operator -d ./charts helm repo index ./charts +delete-helm-gen-manifests: + rm -rf charts/azure-service-operator/templates/generated/ + # Generate manifests e.g. CRD, RBAC etc. manifests: controller-gen $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases diff --git a/PROJECT b/PROJECT index 59918be0af4..85521c1cf3d 100644 --- a/PROJECT +++ b/PROJECT @@ -41,9 +41,6 @@ resources: - group: azure version: v1alpha1 kind: BlobContainer -- group: azure - version: v1alpha1 - kind: AzureDataLakeGen2FileSystem - group: azure version: v1alpha1 kind: PostgreSQLServer @@ -53,6 +50,9 @@ resources: - group: azure version: v1alpha1 kind: PostgreSQLFirewallRule +- group: azure + version: v1alpha1 + kind: PostgreSQLVNetRule - group: azure version: v1alpha1 kind: APIMgmtAPI diff --git a/api/v1alpha1/azuredatalakegen2filesystem_types.go b/api/v1alpha1/azuredatalakegen2filesystem_types.go deleted file mode 100644 index 2e59c0c4431..00000000000 --- a/api/v1alpha1/azuredatalakegen2filesystem_types.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package v1alpha1 - -import ( - helpers "github.com/Azure/azure-service-operator/pkg/helpers" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - -// AzureDataLakeGen2FileSystemSpec defines the desired state of AzureDataLakeGen2FileSystem -type AzureDataLakeGen2FileSystemSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - StorageAccountName string `json:"storageAccountName,omitempty"` - ResourceGroupName string `json:"resourceGroup"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -// AzureDataLakeGen2FileSystem is the Schema for the azuredatalakegen2filesystems API -// +kubebuilder:printcolumn:name="Provisioned",type="string",JSONPath=".status.provisioned" -// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message" -type AzureDataLakeGen2FileSystem struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec AzureDataLakeGen2FileSystemSpec `json:"spec,omitempty"` - Status ASOStatus `json:"status,omitempty"` - Output AzureDataLakeGen2FileSystemOutput `json:"output,omitempty"` -} - -// AzureDataLakeGen2FileSystemOutput is the object that contains the output from creating and AdlsGen2 object -type AzureDataLakeGen2FileSystemOutput struct { - AzureDataLakeGen2FileSystemName string `json:"AzureDataLakeGen2FileSystemName,omitempty"` - Key1 string `json:"key1,omitempty"` - Key2 string `json:"key2,omitempty"` - ConnectionString1 string `json:"connectionString1,omitempty"` - ConnectionString2 string `json:"connectionString2,omitempty"` -} - -// +kubebuilder:object:root=true - -// AzureDataLakeGen2FileSystemList contains a list of AzureDataLakeGen2FileSystem -type AzureDataLakeGen2FileSystemList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []AzureDataLakeGen2FileSystem `json:"items"` -} - -func init() { - SchemeBuilder.Register(&AzureDataLakeGen2FileSystem{}, &AzureDataLakeGen2FileSystemList{}) -} - -// IsSubmitted checks to see if resource has been successfully submitted for creation -func (fs *AzureDataLakeGen2FileSystem) IsSubmitted() bool { - return fs.Status.Provisioning || fs.Status.Provisioned -} - -// HasFinalizer checks to see if the finalizer exists on the instance -func (fs *AzureDataLakeGen2FileSystem) HasFinalizer(finalizerName string) bool { - return helpers.ContainsString(fs.ObjectMeta.Finalizers, finalizerName) -} - -// IsBeingDeleted checks to see if the object is being deleted by checking the DeletionTimestamp -func (fs *AzureDataLakeGen2FileSystem) IsBeingDeleted() bool { - return !fs.ObjectMeta.DeletionTimestamp.IsZero() -} diff --git a/api/v1alpha1/azuresqldatabase_types.go b/api/v1alpha1/azuresqldatabase_types.go index b1443ae9fd9..6319a500b66 100644 --- a/api/v1alpha1/azuresqldatabase_types.go +++ b/api/v1alpha1/azuresqldatabase_types.go @@ -89,7 +89,3 @@ func (s *AzureSqlDatabase) IsSubmitted() bool { func (s *AzureSqlDatabase) HasFinalizer(finalizerName string) bool { return helpers.ContainsString(s.ObjectMeta.Finalizers, finalizerName) } - -func (s *AzureSqlDatabase) IsBeingDeleted() bool { - return !s.ObjectMeta.DeletionTimestamp.IsZero() -} diff --git a/api/v1alpha1/blobcontainer_types.go b/api/v1alpha1/blobcontainer_types.go index 1dc36b58d52..42b8d50f642 100644 --- a/api/v1alpha1/blobcontainer_types.go +++ b/api/v1alpha1/blobcontainer_types.go @@ -59,7 +59,3 @@ func (bc *BlobContainer) IsProvisioned() bool { func (bc *BlobContainer) HasFinalizer(finalizerName string) bool { return helpers.ContainsString(bc.ObjectMeta.Finalizers, finalizerName) } - -func (bc *BlobContainer) IsBeingDeleted() bool { - return !bc.ObjectMeta.DeletionTimestamp.IsZero() -} diff --git a/api/v1alpha1/consumergroup_types.go b/api/v1alpha1/consumergroup_types.go index 4617cd5e405..2e3d06805cf 100644 --- a/api/v1alpha1/consumergroup_types.go +++ b/api/v1alpha1/consumergroup_types.go @@ -52,10 +52,6 @@ func init() { SchemeBuilder.Register(&ConsumerGroup{}, &ConsumerGroupList{}) } -func (consumerGroup *ConsumerGroup) IsBeingDeleted() bool { - return !consumerGroup.ObjectMeta.DeletionTimestamp.IsZero() -} - func (consumerGroup *ConsumerGroup) IsSubmitted() bool { return consumerGroup.Status.Provisioning || consumerGroup.Status.Provisioned diff --git a/api/v1alpha1/cosmosdb_types.go b/api/v1alpha1/cosmosdb_types.go index e483810ba31..b74e1504abe 100644 --- a/api/v1alpha1/cosmosdb_types.go +++ b/api/v1alpha1/cosmosdb_types.go @@ -23,6 +23,7 @@ type CosmosDBSpec struct { Properties CosmosDBProperties `json:"properties,omitempty"` VirtualNetworkRules *[]CosmosDBVirtualNetworkRule `json:"virtualNetworkRules,omitempty"` KeyVaultToStoreSecrets string `json:"keyVaultToStoreSecrets,omitempty"` + Locations *[]CosmosDBLocation `json:"locations,omitempty"` IPRules *[]string `json:"ipRules,omitempty"` } @@ -45,9 +46,17 @@ type CosmosDBProperties struct { // DatabaseAccountOfferType - The offer type for the Cosmos DB database account. DatabaseAccountOfferType CosmosDBDatabaseAccountOfferType `json:"databaseAccountOfferType,omitempty"` // IsVirtualNetworkFilterEnabled - Flag to indicate whether to enable/disable Virtual Network ACL rules. - IsVirtualNetworkFilterEnabled bool `json:"isVirtualNetworkFilterEnabled,omitempty"` - EnableMultipleWriteLocations bool `json:"enableMultipleWriteLocations,omitempty"` - MongoDBVersion string `json:"mongoDBVersion,omitempty"` + IsVirtualNetworkFilterEnabled bool `json:"isVirtualNetworkFilterEnabled,omitempty"` + EnableMultipleWriteLocations bool `json:"enableMultipleWriteLocations,omitempty"` + MongoDBVersion string `json:"mongoDBVersion,omitempty"` + Capabilities *[]Capability `json:"capabilities,omitempty"` +} + +// Capability cosmos DB capability object +type Capability struct { + //Name *CosmosCapability `json:"name,omitempty"` + // +kubebuilder:validation:Enum=EnableCassandra;EnableTable;EnableGremlin;EnableMongo; + Name *string `json:"name,omitempty"` } // +kubebuilder:validation:Enum=Standard @@ -58,13 +67,12 @@ const ( CosmosDBDatabaseAccountOfferTypeStandard CosmosDBDatabaseAccountOfferType = "Standard" ) -/* +// CosmosDBLocation defines one or more locations for geo-redundancy and high availability type CosmosDBLocation struct { - FailoverPriority int `json:"failoverPriority,omitempty"` - LocationName string `json:"locationName,omitempty"` + LocationName string `json:"locationName"` + FailoverPriority int32 `json:"failoverPriority"` IsZoneRedundant bool `json:"isZoneRedundant,omitempty"` } -*/ // +kubebuilder:object:root=true // +kubebuilder:subresource:status diff --git a/api/v1alpha1/eventhub_types.go b/api/v1alpha1/eventhub_types.go index 1e1bd5aca9e..77aab0fc483 100644 --- a/api/v1alpha1/eventhub_types.go +++ b/api/v1alpha1/eventhub_types.go @@ -114,10 +114,6 @@ func init() { SchemeBuilder.Register(&Eventhub{}, &EventhubList{}) } -func (eventhub *Eventhub) IsBeingDeleted() bool { - return !eventhub.ObjectMeta.DeletionTimestamp.IsZero() -} - func (eventhub *Eventhub) IsSubmitted() bool { return eventhub.Status.Provisioning || eventhub.Status.Provisioned } diff --git a/api/v1alpha1/eventhubnamespace_types.go b/api/v1alpha1/eventhubnamespace_types.go index 41c10917ebe..fec65dd909c 100644 --- a/api/v1alpha1/eventhubnamespace_types.go +++ b/api/v1alpha1/eventhubnamespace_types.go @@ -93,10 +93,6 @@ func init() { SchemeBuilder.Register(&EventhubNamespace{}, &EventhubNamespaceList{}) } -func (eventhubNamespace *EventhubNamespace) IsBeingDeleted() bool { - return !eventhubNamespace.ObjectMeta.DeletionTimestamp.IsZero() -} - func (eventhubNamespace *EventhubNamespace) IsSubmitted() bool { return eventhubNamespace.Status.Provisioning || eventhubNamespace.Status.Provisioned diff --git a/api/v1alpha1/mysqlvnetrule_types.go b/api/v1alpha1/mysqlvnetrule_types.go index a4345d0f583..8230da8a98b 100644 --- a/api/v1alpha1/mysqlvnetrule_types.go +++ b/api/v1alpha1/mysqlvnetrule_types.go @@ -25,6 +25,8 @@ type MySQLVNetRuleSpec struct { // +kubebuilder:object:root=true // MySQLVNetRule is the Schema for the mysqlvnetrules API +// +kubebuilder:printcolumn:name="Provisioned",type="string",JSONPath=".status.provisioned" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message" type MySQLVNetRule struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/v1alpha1/postgresqlvnetrule_types.go b/api/v1alpha1/postgresqlvnetrule_types.go new file mode 100644 index 00000000000..6cd37b7a520 --- /dev/null +++ b/api/v1alpha1/postgresqlvnetrule_types.go @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// PotgreSQLVNetRuleSpec defines the desired state of PostgreSQLVNetRule +type PostgreSQLVNetRuleSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + ResourceGroup string `json:"resourceGroup"` + Server string `json:"server"` + VNetResourceGroup string `json:"vNetResourceGroup"` + VNetName string `json:"vNetName"` + SubnetName string `json:"subnetName"` + IgnoreMissingServiceEndpoint bool `json:"ignoreMissingServiceEndpoint,omitempty"` +} + +// +kubebuilder:object:root=true + +// PostgreSQLVNetRule is the Schema for the PostgreSQLVNetRules API +// +kubebuilder:printcolumn:name="Provisioned",type="string",JSONPath=".status.provisioned" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.message" +type PostgreSQLVNetRule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PostgreSQLVNetRuleSpec `json:"spec,omitempty"` + Status ASOStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PostgreSQLVNetRuleList contains a list of PostgreSQLVNetRule +type PostgreSQLVNetRuleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PostgreSQLVNetRule `json:"items"` +} + +func init() { + SchemeBuilder.Register(&PostgreSQLVNetRule{}, &PostgreSQLVNetRuleList{}) +} diff --git a/api/v1alpha1/resourcegroup_types.go b/api/v1alpha1/resourcegroup_types.go index 8cbf2f740e5..77d68c0e02d 100644 --- a/api/v1alpha1/resourcegroup_types.go +++ b/api/v1alpha1/resourcegroup_types.go @@ -45,10 +45,6 @@ func init() { SchemeBuilder.Register(&ResourceGroup{}, &ResourceGroupList{}) } -func (resourceGroup *ResourceGroup) IsBeingDeleted() bool { - return !resourceGroup.ObjectMeta.DeletionTimestamp.IsZero() -} - func (resourceGroup *ResourceGroup) IsSubmitted() bool { return resourceGroup.Status.Provisioning || resourceGroup.Status.Provisioned diff --git a/api/v1alpha1/virtualnetwork_types.go b/api/v1alpha1/virtualnetwork_types.go index 803ba6917d6..1b3f82f122f 100644 --- a/api/v1alpha1/virtualnetwork_types.go +++ b/api/v1alpha1/virtualnetwork_types.go @@ -14,8 +14,9 @@ import ( type VNetSubnets struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file - SubnetName string `json:"subnetName"` - SubnetAddressPrefix string `json:"subnetAddressPrefix"` + SubnetName string `json:"subnetName"` + SubnetAddressPrefix string `json:"subnetAddressPrefix"` + ServiceEndpoints []string `json:"serviceEndpoints,omitempty"` } // VirtualNetworkSpec defines the desired state of VirtualNetwork diff --git a/charts/azure-service-operator-0.1.0.tgz b/charts/azure-service-operator-0.1.0.tgz new file mode 100644 index 00000000000..a054aac8e41 Binary files /dev/null and b/charts/azure-service-operator-0.1.0.tgz differ diff --git a/charts/azure-service-operator/Chart.yaml b/charts/azure-service-operator/Chart.yaml index b4be166f4f2..2c370773eac 100644 --- a/charts/azure-service-operator/Chart.yaml +++ b/charts/azure-service-operator/Chart.yaml @@ -1,4 +1,4 @@ -apiVersion: v1 +apiVersion: v2 name: azure-service-operator version: 0.1.0 appVersion: 0.1.0 diff --git a/charts/azure-service-operator/README.md b/charts/azure-service-operator/README.md index bd25ebd35bd..e5cbde6b4bb 100644 --- a/charts/azure-service-operator/README.md +++ b/charts/azure-service-operator/README.md @@ -74,6 +74,11 @@ If you are deploying into an already created namespace, be sure to set the follo createNamespace: False ``` +and specify the namespace name: +``` +namespace: your-namespace +``` + Finally, install the chart with your added values. The chart can be installed by using a values file or environment variables. ``` helm upgrade --install aso azureserviceoperator/azure-service-operator -f values.yaml @@ -102,7 +107,9 @@ The following table lists the configurable parameters of the azure-service-opera | `azureClientSecret` | Azure Service Principal Client Secret | `` | | `azureUseMI` | Set to True if using Managed Identity for authentication | `False` | | `azureOperatorKeyvault` | Set this value with the name of your Azure Key Vault resource if you prefer to store secrets in Key Vault rather than as Kubernetes secrets (default) | `` | -| `image.repository` | Image repository | `mcr.microsoft.com/k8s/azure-service-operator:0.0.9150` | -| `createNamespace` | Set to True if you would like the namespace autocreated, otherwise False if you have an existing namespace | `True` | +| `image.repository` | Image repository | `mcr.microsoft.com/k8s/azure-service-operator:0.0.20258` | +| `cloudEnvironment` | Set the cloud environment, possible values include: AzurePublicCloud, AzureUSGovernmentCloud, AzureChinaCloud, AzureGermanCloud | `AzurePublicCloud` | +| `createNamespace` | Set to True if you would like the namespace autocreated, otherwise False if you have an existing namespace. If using an existing namespace, the `namespace` field must also be updated | `True` | +| `namespace` | Configure a custom namespace to deploy the operator into | `azureoperator-system` | | `aad-pod-identity.azureIdentity.resourceID` | The resource ID for your managed identity | `` | | `aad-pod-identity.azureIdentity.clientID` | The client ID for your managed identity | `` | \ No newline at end of file diff --git a/charts/azure-service-operator/charts/aad-pod-identity-1.5.5.tgz b/charts/azure-service-operator/charts/aad-pod-identity-1.5.5.tgz new file mode 100644 index 00000000000..7e1aeab41bf Binary files /dev/null and b/charts/azure-service-operator/charts/aad-pod-identity-1.5.5.tgz differ diff --git a/charts/azure-service-operator/requirements.lock b/charts/azure-service-operator/requirements.lock new file mode 100644 index 00000000000..c457c262f9f --- /dev/null +++ b/charts/azure-service-operator/requirements.lock @@ -0,0 +1,6 @@ +dependencies: +- name: aad-pod-identity + repository: https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts + version: 1.5.5 +digest: sha256:db38bea05230aea212e9ab0f056a1defa73d540bbff2962e807b2fd860dddf3d +generated: "2020-04-22T10:23:15.164357-07:00" diff --git a/charts/azure-service-operator/templates/namespace.yaml b/charts/azure-service-operator/templates/namespace.yaml index 4263087062e..1651a617a02 100644 --- a/charts/azure-service-operator/templates/namespace.yaml +++ b/charts/azure-service-operator/templates/namespace.yaml @@ -4,5 +4,5 @@ kind: Namespace metadata: labels: control-plane: controller-manager - name: azureoperator-system + name: {{ .Values.namespace }} {{- end }} \ No newline at end of file diff --git a/charts/azure-service-operator/templates/secret.yaml b/charts/azure-service-operator/templates/secret.yaml index 6b368883b51..e690ca2c457 100644 --- a/charts/azure-service-operator/templates/secret.yaml +++ b/charts/azure-service-operator/templates/secret.yaml @@ -2,11 +2,12 @@ apiVersion: v1 kind: Secret metadata: name: azureoperatorsettings - namespace: azureoperator-system + namespace: {{ .Values.namespace }} type: Opaque data: AZURE_SUBSCRIPTION_ID: {{ .Values.azureSubscriptionID | b64enc | quote }} AZURE_TENANT_ID: {{ .Values.azureTenantID | b64enc | quote }} + AZURE_CLOUD_ENV: {{ .Values.cloudEnvironment | b64enc | quote }} {{- if .Values.azureClientID }} AZURE_CLIENT_ID: {{ .Values.azureClientID | b64enc | quote }} diff --git a/charts/azure-service-operator/values.yaml b/charts/azure-service-operator/values.yaml index c3fbd0c18a6..26606d8c12b 100644 --- a/charts/azure-service-operator/values.yaml +++ b/charts/azure-service-operator/values.yaml @@ -7,6 +7,12 @@ azureOperatorKeyvault: "" # Set to False if you do not need the namespace autocreated createNamespace: True +# Optional, Custom Namespace +namespace: azureoperator-system + +# Set the cloud environment, possible values include: AzurePublicCloud, AzureUSGovernmentCloud, AzureChinaCloud, AzureGermanCloud +cloudEnvironment: AzurePublicCloud + # Authentication - Service Principal azureClientID: "" azureClientSecret: "" @@ -15,7 +21,7 @@ azureClientSecret: "" azureUseMI: False image: - repository: mcr.microsoft.com/k8s/azure-service-operator:0.0.13046 + repository: mcr.microsoft.com/k8s/azure-service-operator:0.0.20258 aad-pod-identity: azureIdentityBinding: diff --git a/charts/index.yaml b/charts/index.yaml index 6816e4b7cd0..e7a7bfe917c 100644 --- a/charts/index.yaml +++ b/charts/index.yaml @@ -1,11 +1,16 @@ apiVersion: v1 entries: azure-service-operator: - - apiVersion: v1 + - apiVersion: v2 appVersion: 0.1.0 - created: "2020-03-09T14:47:12.306231-05:00" + created: "2020-04-23T11:50:42.794582-07:00" + dependencies: + - condition: azureUseMI + name: aad-pod-identity + repository: https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts + version: 1.5.5 description: Deploy components and dependencies of azure-service-operator - digest: 4fbc8ed33b694e9a239b4b5c3e0903a23c731f1fd2d5e8a040488f780487bf87 + digest: 6aaf972ecdc1aad3c0e9b4c414d8b39cc33c40f17ef8b8985b3c8acfac80bc72 home: https://github.com/Azure/azure-service-operator name: azure-service-operator sources: @@ -13,4 +18,4 @@ entries: urls: - azure-service-operator-0.1.0.tgz version: 0.1.0 -generated: "2020-03-09T14:47:12.302559-05:00" +generated: "2020-04-23T11:50:42.791883-07:00" diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 22f54886eb2..5923dfd3bb8 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -17,11 +17,11 @@ resources: - bases/azure.microsoft.com_azuresqlactions.yaml - bases/azure.microsoft.com_azuresqlfailovergroups.yaml - bases/azure.microsoft.com_blobcontainers.yaml -- bases/azure.microsoft.com_azuredatalakegen2filesystems.yaml - bases/azure.microsoft.com_appinsights.yaml - bases/azure.microsoft.com_postgresqlservers.yaml - bases/azure.microsoft.com_postgresqldatabases.yaml - bases/azure.microsoft.com_postgresqlfirewallrules.yaml +- bases/azure.microsoft.com_postgresqlvnetrules.yaml - bases/azure.microsoft.com_apimservices.yaml - bases/azure.microsoft.com_apimgmtapis.yaml - bases/azure.microsoft.com_virtualnetworks.yaml @@ -51,11 +51,11 @@ resources: #- patches/webhook_in_azuresqlactions.yaml #- patches/webhook_in_azuresqlfailovergroups.yaml #- patches/webhook_in_blobcontainers.yaml -#- patches/webhook_in_azuredatalakegen2filesystems.yaml #- patches/webhook_in_appinsights.yaml #- patches/webhook_in_postgresqlservers.yaml #- patches/webhook_in_postgresqldatabases.yaml #- patches/webhook_in_postgresqlfirewallrules.yaml +#- patches/webhook_in_postgresqlvnetrules.yaml #- patches/webhook_in_apimservices.yaml #- patches/webhook_in_apimgmtapis.yaml #- patches/webhook_in_virtualnetworks.yaml @@ -84,11 +84,11 @@ resources: #- patches/cainjection_in_azuresqlactions.yaml #- patches/cainjection_in_azuresqlfailovergroups.yaml #- patches/cainjection_in_blobcontainers.yaml -#- patches/cainjection_in_azuredatalakegen2filesystems.yaml #- patches/cainjection_in_appinsights.yaml #- patches/cainjection_in_postgresqlservers.yaml #- patches/cainjection_in_postgresqldatabases.yaml #- patches/cainjection_in_postgresqlfirewallrules.yaml +#- patches/cainjection_in_postgresqlvnetrules.yaml #- patches/cainjection_in_apimservices.yaml #- patches/cainjection_in_apimgmtapis.yaml #- patches/cainjection_in_virtualnetworks.yaml diff --git a/config/crd/patches/cainjection_in_azuredatalakegen2filesystems.yaml b/config/crd/patches/cainjection_in_postgresqlvnetrules.yaml similarity index 61% rename from config/crd/patches/cainjection_in_azuredatalakegen2filesystems.yaml rename to config/crd/patches/cainjection_in_postgresqlvnetrules.yaml index 4679703f2cf..13ff16ea354 100644 --- a/config/crd/patches/cainjection_in_azuredatalakegen2filesystems.yaml +++ b/config/crd/patches/cainjection_in_postgresqlvnetrules.yaml @@ -4,5 +4,5 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: azuredatalakegen2filesystems.azure.microsoft.com + certmanager.k8s.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: postgresqlvnetrules.azure.microsoft.com diff --git a/config/crd/patches/webhook_in_azuredatalakegen2filesystems.yaml b/config/crd/patches/webhook_in_postgresqlvnetrules.yaml similarity index 91% rename from config/crd/patches/webhook_in_azuredatalakegen2filesystems.yaml rename to config/crd/patches/webhook_in_postgresqlvnetrules.yaml index aa227bf11db..0137abcbfa6 100644 --- a/config/crd/patches/webhook_in_azuredatalakegen2filesystems.yaml +++ b/config/crd/patches/webhook_in_postgresqlvnetrules.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: azuredatalakegen2filesystems.azure.microsoft.com + name: postgresqlvnetrules.azure.microsoft.com spec: conversion: strategy: Webhook diff --git a/config/samples/azure_v1alpha1_azuredatalakegen2filesystem.yaml b/config/samples/azure_v1alpha1_azuredatalakegen2filesystem.yaml deleted file mode 100644 index e5f5910db71..00000000000 --- a/config/samples/azure_v1alpha1_azuredatalakegen2filesystem.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: azure.microsoft.com/v1alpha1 -kind: AzureDataLakeGen2FileSystem -metadata: - name: adls-filesystem-sample -spec: - storageAccountName: adlsaccountsample - resourceGroup: resourcegroup-azure-operators diff --git a/config/samples/azure_v1alpha1_azuredatalakegen2storage.yaml b/config/samples/azure_v1alpha1_azuredatalakegen2storage.yaml deleted file mode 100644 index 2a3fd7e6881..00000000000 --- a/config/samples/azure_v1alpha1_azuredatalakegen2storage.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: azure.microsoft.com/v1alpha1 -kind: StorageAccount -metadata: - name: adlsaccountsample -spec: - location: westus - resourceGroup: resourcegroup-azure-operators - sku: - name: Standard_LRS - kind: StorageV2 - accessTier: Hot - supportsHttpsTrafficOnly: true - dataLakeEnabled: true diff --git a/config/samples/azure_v1alpha1_cosmosdb.yaml b/config/samples/azure_v1alpha1_cosmosdb.yaml index e4b857a7a66..afd74e26486 100644 --- a/config/samples/azure_v1alpha1_cosmosdb.yaml +++ b/config/samples/azure_v1alpha1_cosmosdb.yaml @@ -8,7 +8,15 @@ spec: resourceGroup: resourcegroup-azure-operators properties: databaseAccountOfferType: Standard - enableMultipleWriteLocations: false + + # optionally turn on multi-region writes + # enableMultipleWriteLocations: true + + # Optionally set the capabilities name to the following options: (the default is SQL) + # "EnableCassandra", "EnableTable", "EnableGremlin", "EnableMongo" + # NOTE: If using "EnableMongo" kind must be set to MongoDB for this to take effect + #capabilities: + # - name: "EnableCassandra" # optionally set the mongoDBVersion to "3.2" or "3.6", if omitted the default is "3.2" # NOTE: kind must be set to MongoDB for this to take effect @@ -27,4 +35,12 @@ spec: # # the ips in this rule are needed to access your db from the portal # - 104.42.195.92,40.76.54.131,52.176.6.30,52.169.50.45,52.187.184.26 # # add additional ips you would like to grant access - # - 73.153.28.188 \ No newline at end of file + # - 1.2.3.4 + + # optionally configure multiple regions and availability zone redundancy + # locations: + # - locationName: eastus + # failoverPriority: 0 + # isZoneRedundant: true + # - locationName: westus + # failoverPriority: 1 \ No newline at end of file diff --git a/config/samples/azure_v1alpha1_cosmosdb_prod.yaml b/config/samples/azure_v1alpha1_cosmosdb_prod.yaml new file mode 100644 index 00000000000..1d328ebf2eb --- /dev/null +++ b/config/samples/azure_v1alpha1_cosmosdb_prod.yaml @@ -0,0 +1,48 @@ +apiVersion: azure.microsoft.com/v1alpha1 +kind: CosmosDB +metadata: + name: cosmosdb-sample-2 + labels: + CosmosAccountType: Production +spec: + kind: GlobalDocumentDB + location: eastus + resourceGroup: resourcegroup-azure-operators + properties: + databaseAccountOfferType: Standard + + # turn on multi-region writes for production + enableMultipleWriteLocations: true + + # Optionally set the capabilities name to the following options: (the default is SQL) + # "EnableCassandra", "EnableTable", "EnableGremlin", "EnableMongo" + # NOTE: If using "EnableMongo" kind must be set to MongoDB for this to take effect + #capabilities: + # - name: "EnableCassandra" + + # optionally set the mongoDBVersion to "3.2" or "3.6", if omitted the default is "3.2" + # NOTE: kind must be set to MongoDB for this to take effect + # mongoDBVersion: "3.6" + + # enable virtual network rules if configured below + # isVirtualNetworkFilterEnabled: true + + # optionally restrict access to specific virtual networks + # virtualNetworkRules: + # - subnetId: /subscriptions/{subscription_id}/resourceGroups/{resourcegroup}/providers/Microsoft.Network/virtualNetworks/{vnet_name}/subnets/{subnet_name} + # ignoreMissingServiceEndpoint: false + + # optionally configure different CIDR IP ranges for allowed-list, omitting allows all or falls back to vNetRules + ipRules: + # the ips in this rule are needed to access your db from the portal + - 104.42.195.92,40.76.54.131,52.176.6.30,52.169.50.45,52.187.184.26 + # # add additional ips you would like to grant access + # - 1.2.3.4 + + # configure multiple regions and availability zone redundancy + locations: + - locationName: eastus + failoverPriority: 0 + isZoneRedundant: true + - locationName: westus + failoverPriority: 1 \ No newline at end of file diff --git a/config/samples/azure_v1alpha1_postgresqlserver.yaml b/config/samples/azure_v1alpha1_postgresqlserver.yaml index f4ac4bfcb33..47c6b8aebf4 100644 --- a/config/samples/azure_v1alpha1_postgresqlserver.yaml +++ b/config/samples/azure_v1alpha1_postgresqlserver.yaml @@ -3,16 +3,16 @@ kind: PostgreSQLServer metadata: name: postgresqlserver-sample spec: - location: westus2 + location: eastus resourceGroup: resourcegroup-azure-operators serverVersion: "10" sslEnforcement: Enabled sku: - name: B_Gen5_2 - tier: Basic + name: GP_Gen5_4 # tier + family + cores eg. - B_Gen4_1, GP_Gen5_4 + tier: GeneralPurpose # possible values - 'Basic', 'GeneralPurpose', 'MemoryOptimized' family: Gen5 size: "51200" - capacity: 2 + capacity: 4 # Use the field below to optionally specify a different keyvault # to store the server admin credential secrets in #keyVaultToStoreSecrets: asoSecretKeyVault \ No newline at end of file diff --git a/config/samples/azure_v1alpha1_postgresqlvnetrule.yaml b/config/samples/azure_v1alpha1_postgresqlvnetrule.yaml new file mode 100644 index 00000000000..2195e8f978f --- /dev/null +++ b/config/samples/azure_v1alpha1_postgresqlvnetrule.yaml @@ -0,0 +1,11 @@ +apiVersion: azure.microsoft.com/v1alpha1 +kind: PostgreSQLVNetRule +metadata: + name: postgresqlvnetrule-sample1 +spec: + resourceGroup: resourcegroup-azure-operators + server: postgresqlserver-sample + vNetResourceGroup: resourcegroup-azure-operators + vNetName: virtualnetwork-sample + subnetName: test1 + ignoreMissingServiceEndpoint: true diff --git a/config/samples/azure_v1alpha1_virtualnetwork.yaml b/config/samples/azure_v1alpha1_virtualnetwork.yaml index ce3185ec47a..875c5ef3c20 100644 --- a/config/samples/azure_v1alpha1_virtualnetwork.yaml +++ b/config/samples/azure_v1alpha1_virtualnetwork.yaml @@ -11,3 +11,7 @@ spec: subnetAddressPrefix: "10.1.0.0/16" - subnetName: test2 subnetAddressPrefix: "10.2.0.0/16" + # Optional: enable service endpoints + # serviceEndpoints: + # - Microsoft.Storage + # - Microsoft.Sql \ No newline at end of file diff --git a/controllers/azuredatalakegen2filesystem_controller.go b/controllers/azuredatalakegen2filesystem_controller.go deleted file mode 100644 index 6dbc25f9ecf..00000000000 --- a/controllers/azuredatalakegen2filesystem_controller.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package controllers - -import ( - "context" - "fmt" - "os" - "strconv" - "time" - - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/errhelp" - "github.com/Azure/azure-service-operator/pkg/helpers" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages" - "github.com/Azure/go-autorest/autorest/to" - "github.com/go-logr/logr" - v1 "k8s.io/api/core/v1" - "k8s.io/client-go/tools/record" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const fileSystemFinalizerName = "filesystem.finalizers.azure.com" - -// AzureDataLakeGen2FileSystemReconciler reconciles a AzureDataLakeGen2FileSystem object -type AzureDataLakeGen2FileSystemReconciler struct { - client.Client - Log logr.Logger - Recorder record.EventRecorder - RequeueTime time.Duration - FileSystemManager storages.FileSystemManager -} - -// +kubebuilder:rbac:groups=azure.microsoft.com,resources=azuredatalakegen2filesystems,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=azure.microsoft.com,resources=azuredatalakegen2filesystems/status,verbs=get;update;patch - -func (r *AzureDataLakeGen2FileSystemReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - log := r.Log.WithValues("adlsgen2FileSystem", req.NamespacedName) - - var instance azurev1alpha1.AzureDataLakeGen2FileSystem - - requeueAfter, err := strconv.Atoi(os.Getenv("REQUEUE_AFTER")) - if err != nil { - requeueAfter = 30 - } - - if err := r.Get(ctx, req.NamespacedName, &instance); err != nil { - log.Info("unable to retrieve ADLS Gen2 resource", "err", err.Error()) - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - if helpers.IsBeingDeleted(&instance) { - if HasFinalizer(&instance, fileSystemFinalizerName) { - if err := r.deleteExternal(&instance); err != nil { - log.Info("Error", "Delete Storage failed with ", err) - return ctrl.Result{}, err - } - - RemoveFinalizer(&instance, fileSystemFinalizerName) - if err := r.Update(context.Background(), &instance); err != nil { - return ctrl.Result{}, err - } - } - return ctrl.Result{}, nil - } - - if !HasFinalizer(&instance, fileSystemFinalizerName) { - err := r.addFinalizer(&instance) - if err != nil { - return ctrl.Result{}, fmt.Errorf("error when adding finalizer: %v", err) - } - return ctrl.Result{}, nil - } - - if !instance.IsSubmitted() { - err := r.reconcileExternal(&instance) - if err != nil { - catch := []string{ - errhelp.ParentNotFoundErrorCode, - errhelp.ResourceGroupNotFoundErrorCode, - errhelp.ResourceNotFound, - } - azerr := errhelp.NewAzureErrorAzureError(err) - if helpers.ContainsString(catch, azerr.Type) { - log.Info("Got ignorable error", "type", err.(*errhelp.AzureError).Type) - return ctrl.Result{Requeue: true, RequeueAfter: time.Second * time.Duration(requeueAfter)}, nil - } - return ctrl.Result{}, fmt.Errorf("error when creating resource in azure: %v", err) - } - return ctrl.Result{}, nil - } - - return ctrl.Result{}, nil -} - -func (r *AzureDataLakeGen2FileSystemReconciler) addFinalizer(instance *azurev1alpha1.AzureDataLakeGen2FileSystem) error { - AddFinalizer(instance, fileSystemFinalizerName) - err := r.Update(context.Background(), instance) - if err != nil { - return fmt.Errorf("failed to update finalizer: %v", err) - } - r.Recorder.Event(instance, v1.EventTypeNormal, "Updated", fmt.Sprintf("finalizer %s added", fileSystemFinalizerName)) - return nil -} - -func (r *AzureDataLakeGen2FileSystemReconciler) reconcileExternal(instance *azurev1alpha1.AzureDataLakeGen2FileSystem) error { - ctx := context.Background() - storageAccountName := instance.Spec.StorageAccountName - groupName := instance.Spec.ResourceGroupName - fileSystemName := instance.ObjectMeta.Name - xMsDate := time.Now().String() - - var err error - - // write info back to instance - instance.Status.Provisioning = true - - err = r.Status().Update(ctx, instance) - if err != nil { - r.Recorder.Event(instance, v1.EventTypeWarning, "Failed", "unable to update instance") - } - - _, err = r.FileSystemManager.CreateFileSystem(ctx, groupName, fileSystemName, to.Int32Ptr(20), xMsDate, storageAccountName) - if err != nil { - r.Recorder.Event(instance, v1.EventTypeWarning, "Failed", "Couldn't create resource in azure") - instance.Status.Provisioning = false - errUpdate := r.Update(ctx, instance) - if errUpdate != nil { - //log error and kill it - r.Recorder.Event(instance, v1.EventTypeWarning, "Failed", "Unable to update instance") - return err - } - - return errhelp.NewAzureError(err) - } - - instance.Status.Provisioning = false - instance.Status.Provisioned = true - - err = r.Status().Update(ctx, instance) - if err != nil { - r.Recorder.Event(instance, v1.EventTypeWarning, "Failed", "Unable to update instance") - } - - r.Recorder.Event(instance, v1.EventTypeNormal, "Updated", fileSystemName+" provisioned") - - return nil -} - -func (r *AzureDataLakeGen2FileSystemReconciler) deleteExternal(instance *azurev1alpha1.AzureDataLakeGen2FileSystem) error { - ctx := context.Background() - fileSystemName := instance.ObjectMeta.Name - groupName := instance.Spec.ResourceGroupName - storageAccountName := instance.Spec.StorageAccountName - xMsDate := time.Now().String() - timeout := to.Int32Ptr(40) - - _, err := r.FileSystemManager.DeleteFileSystem(ctx, groupName, fileSystemName, timeout, xMsDate, storageAccountName) - if err != nil { - if errhelp.IsStatusCode204(err) || errhelp.IsStatusCode404(err) { - r.Recorder.Event(instance, "Warning", "DoesNotExist", "Resource to delete does not exist") - return nil - } - - r.Recorder.Event(instance, v1.EventTypeWarning, "Failed", "Couldn't delete resource in azure") - return err - } - - r.Recorder.Event(instance, v1.EventTypeNormal, "Deleted", fileSystemName+" deleted") - - return nil -} - -// SetupWithManager sets up the controller functions -func (r *AzureDataLakeGen2FileSystemReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&azurev1alpha1.AzureDataLakeGen2FileSystem{}). - Complete(r) -} diff --git a/controllers/azuredatalakegen2filesystem_controller_test.go b/controllers/azuredatalakegen2filesystem_controller_test.go deleted file mode 100644 index 0eb87b83118..00000000000 --- a/controllers/azuredatalakegen2filesystem_controller_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -// +build all adlsgen2 - -package controllers - -import ( - "context" - "testing" - - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/helpers" - "github.com/stretchr/testify/assert" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" -) - -/*func TestADLSFilesystemControllerNoResourceGroup(t *testing.T) { - t.Parallel() - defer PanicRecover(t) - assert := assert.New(t) - ctx := context.Background() - - var saName string = tc.storageAccountName - - // Add Tests for OpenAPI validation (or additonal CRD features) specified in - // your API definition. - // Avoid adding tests for vanilla CRUD operations because they would - // test Kubernetes API server, which isn't the goal here. - - fileSystemName := "adls-filesystem-" + helpers.RandomString(10) - resouceGroupName := "rg-" + helpers.RandomString(10) - - var err error - - fileSystemInstance := &azurev1alpha1.AzureDataLakeGen2FileSystem{ - ObjectMeta: metav1.ObjectMeta{ - Name: fileSystemName, - Namespace: "default", - }, - Spec: azurev1alpha1.AzureDataLakeGen2FileSystemSpec{ - StorageAccountName: saName, - ResourceGroupName: resouceGroupName, - }, - } - - err = tc.k8sClient.Create(ctx, fileSystemInstance) - assert.Equal(nil, err, "create filesystem instance in k8s") - - // @todo update this to check something other than status.Provisioned - fileSystemNamespacedName := types.NamespacedName{Name: fileSystemName, Namespace: "default"} - - assert.Eventually(func() bool { - _ = tc.k8sClient.Get(ctx, fileSystemNamespacedName, fileSystemInstance) - return fileSystemInstance.Status.Provisioned == false - }, tc.timeout, tc.retry, "wait for filesystem to have false for provisioned bool") - - // Delete should still appear successful - err = tc.k8sClient.Delete(ctx, fileSystemInstance) - assert.Equal(nil, err, "delete filesystem instance in k8s") - - assert.Eventually(func() bool { - err = tc.k8sClient.Get(ctx, fileSystemNamespacedName, fileSystemInstance) - return apierrors.IsNotFound(err) - }, tc.timeout, tc.retry, "wait for filesystem to be gone") - -}*/ - -func TestADLSFilesystemControllerNoStorageAccount(t *testing.T) { - t.Parallel() - defer PanicRecover(t) - assert := assert.New(t) - ctx := context.Background() - - var rgName string = tc.resourceGroupName - fileSystemName := "adls-filesystem-" + helpers.RandomString(10) - storageAccountName := "sa-" + helpers.RandomString(10) - - var err error - - fileSystemInstance := &azurev1alpha1.AzureDataLakeGen2FileSystem{ - ObjectMeta: metav1.ObjectMeta{ - Name: fileSystemName, - Namespace: "default", - }, - Spec: azurev1alpha1.AzureDataLakeGen2FileSystemSpec{ - StorageAccountName: storageAccountName, - ResourceGroupName: rgName, - }, - } - - err = tc.k8sClient.Create(ctx, fileSystemInstance) - assert.Equal(nil, err, "create filesystem instance in k8s") - - fileSystemNamespacedName := types.NamespacedName{Name: fileSystemName, Namespace: "default"} - - assert.Eventually(func() bool { - _ = tc.k8sClient.Get(ctx, fileSystemNamespacedName, fileSystemInstance) - return fileSystemInstance.Status.Provisioned == false - }, tc.timeout, tc.retry, "wait for filesystem to have false for provisioned bool") - - // Delete should still appear successful - err = tc.k8sClient.Delete(context.Background(), fileSystemInstance) - assert.Equal(nil, err, "delete filesystem instance in k8s") - - assert.Eventually(func() bool { - err = tc.k8sClient.Get(ctx, fileSystemNamespacedName, fileSystemInstance) - return apierrors.IsNotFound(err) - }, tc.timeout, tc.retry, "wait for filesystem to be gone") -} - -// func TestADLSFilesystemControllerHappyPath(t *testing.T) { -// t.Parallel() -// RegisterTestingT(t) -// defer PanicRecover() - -// var rgName string = tc.resourceGroupName -// var saName string = tc.storageAccountName - -// fileSystemName := "adls-filesystem-" + helpers.RandomString(10) - -// var err error - -// fileSystemInstance := &azurev1alpha1.AzureDataLakeGen2FileSystem{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: fileSystemName, -// Namespace: "default", -// }, -// Spec: azurev1alpha1.AzureDataLakeGen2FileSystemSpec{ -// StorageAccountName: saName, -// ResourceGroupName: rgName, -// }, -// } - -// err = tc.k8sClient.Create(context.Background(), fileSystemInstance) -// Expect(apierrors.IsInvalid(err)).To(Equal(false)) -// Expect(err).NotTo(HaveOccurred()) - -// fileSystemNamespacedName := types.NamespacedName{Name: fileSystemName, Namespace: "default"} - -// Eventually(func() bool { -// _ = tc.k8sClient.Get(context.Background(), fileSystemNamespacedName, fileSystemInstance) -// return fileSystemInstance.HasFinalizer(fileSystemFinalizerName) -// }, tc.timeout, tc.retry, -// ).Should(BeTrue()) - -// Eventually(func() bool { -// _ = tc.k8sClient.Get(context.Background(), fileSystemNamespacedName, fileSystemInstance) -// // return fileSystemInstance.Status.Provisioned -// // this is wrong @todo fix -// return fileSystemInstance.IsSubmitted() -// }, tc.timeout, tc.retry, -// ).Should(BeTrue()) - -// err = tc.k8sClient.Delete(context.Background(), fileSystemInstance) -// Expect(err).NotTo(HaveOccurred()) - -// Eventually(func() bool { -// err = tc.k8sClient.Get(context.Background(), fileSystemNamespacedName, fileSystemInstance) -// //return apierrors.IsNotFound(err) -// return fileSystemInstance.IsBeingDeleted() -// }, tc.timeout, tc.retry, -// ).Should(BeTrue()) - -// } diff --git a/controllers/eventhub_storageaccount_controller_test.go b/controllers/eventhub_storageaccount_controller_test.go index 181c34ed80c..94882a5016d 100644 --- a/controllers/eventhub_storageaccount_controller_test.go +++ b/controllers/eventhub_storageaccount_controller_test.go @@ -55,63 +55,63 @@ func TestEventHubControllerNoNamespace(t *testing.T) { EnsureDelete(ctx, t, tc, eventhubInstance) } -func TestEventHubControllerCreateAndDeleteCustomSecret(t *testing.T) { - t.Parallel() - defer PanicRecover(t) - ctx := context.Background() - - // Add any setup steps that needs to be executed before each test - rgName := tc.resourceGroupName - rgLocation := tc.resourceGroupLocation - ehnName := GenerateTestResourceNameWithRandom("eh-ns", 10) - eventhubName := GenerateTestResourceNameWithRandom("eh-customsec", 10) - secretName := "secret-" + eventhubName - - // Create EventhubNamespace instance as prereq - eventhubNamespaceInstance := &azurev1alpha1.EventhubNamespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: ehnName, - Namespace: "default", - }, - Spec: azurev1alpha1.EventhubNamespaceSpec{ - Location: rgLocation, - ResourceGroup: rgName, - }, - } +// func TestEventHubControllerCreateAndDeleteCustomSecret(t *testing.T) { +// t.Parallel() +// defer PanicRecover(t) +// ctx := context.Background() + +// // Add any setup steps that needs to be executed before each test +// rgName := tc.resourceGroupName +// rgLocation := tc.resourceGroupLocation +// ehnName := GenerateTestResourceNameWithRandom("eh-ns", 10) +// eventhubName := GenerateTestResourceNameWithRandom("eh-customsec", 10) +// secretName := "secret-" + eventhubName + +// // Create EventhubNamespace instance as prereq +// eventhubNamespaceInstance := &azurev1alpha1.EventhubNamespace{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: ehnName, +// Namespace: "default", +// }, +// Spec: azurev1alpha1.EventhubNamespaceSpec{ +// Location: rgLocation, +// ResourceGroup: rgName, +// }, +// } + +// EnsureInstance(ctx, t, tc, eventhubNamespaceInstance) + +// // Create the EventHub object and expect the Reconcile to be created +// eventhubInstance := &azurev1alpha1.Eventhub{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: eventhubName, +// Namespace: "default", +// }, +// Spec: azurev1alpha1.EventhubSpec{ +// Location: rgLocation, +// Namespace: ehnName, +// ResourceGroup: rgName, +// Properties: azurev1alpha1.EventhubProperties{ +// MessageRetentionInDays: 7, +// PartitionCount: 2, +// }, +// AuthorizationRule: azurev1alpha1.EventhubAuthorizationRule{ +// Name: "RootManageSharedAccessKey", +// Rights: []string{"Listen"}, +// }, +// SecretName: secretName, +// }, +// } + +// EnsureInstance(ctx, t, tc, eventhubInstance) + +// EnsureSecretsWithValue(ctx, t, tc, eventhubInstance, tc.secretClient, secretName, eventhubInstance.Namespace, "eventhubName", eventhubName) + +// EnsureDelete(ctx, t, tc, eventhubInstance) + +// EnsureDelete(ctx, t, tc, eventhubNamespaceInstance) +// } - EnsureInstance(ctx, t, tc, eventhubNamespaceInstance) - - // Create the EventHub object and expect the Reconcile to be created - eventhubInstance := &azurev1alpha1.Eventhub{ - ObjectMeta: metav1.ObjectMeta{ - Name: eventhubName, - Namespace: "default", - }, - Spec: azurev1alpha1.EventhubSpec{ - Location: rgLocation, - Namespace: ehnName, - ResourceGroup: rgName, - Properties: azurev1alpha1.EventhubProperties{ - MessageRetentionInDays: 7, - PartitionCount: 2, - }, - AuthorizationRule: azurev1alpha1.EventhubAuthorizationRule{ - Name: "RootManageSharedAccessKey", - Rights: []string{"Listen"}, - }, - SecretName: secretName, - }, - } - - EnsureInstance(ctx, t, tc, eventhubInstance) - - EnsureSecretsWithValue(ctx, t, tc, eventhubInstance, tc.secretClient, secretName, eventhubInstance.Namespace, "eventhubName", eventhubName) - - EnsureDelete(ctx, t, tc, eventhubInstance) - - EnsureDelete(ctx, t, tc, eventhubNamespaceInstance) - -} func TestEventHubControllerCreateAndDeleteCustomKeyVault(t *testing.T) { t.Parallel() defer PanicRecover(t) diff --git a/controllers/eventhubnamespace_controller_test.go b/controllers/eventhubnamespace_controller_test.go index ffc3817d710..5326a5ed4a0 100644 --- a/controllers/eventhubnamespace_controller_test.go +++ b/controllers/eventhubnamespace_controller_test.go @@ -23,8 +23,7 @@ func TestEventHubNamespaceControllerNoResourceGroup(t *testing.T) { var rgLocation string rgLocation = tc.resourceGroupLocation - // setting this rg name tells the mocks to set a proper error - resourceGroupName := "gone" + resourceGroupName := GenerateTestResourceNameWithRandom("rg", 10) eventhubNamespaceName := GenerateTestResourceNameWithRandom("ns-dev-eh", 10) // Create the EventHubNamespace object and expect the Reconcile to be created diff --git a/controllers/postgresqlvnetrule_controller.go b/controllers/postgresqlvnetrule_controller.go new file mode 100644 index 00000000000..e7c5772f7d1 --- /dev/null +++ b/controllers/postgresqlvnetrule_controller.go @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package controllers + +import ( + ctrl "sigs.k8s.io/controller-runtime" + + azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" +) + +// PostgreSQLVNetRuleReconciler reconciles a PostgreSQLVNetRule object +type PostgreSQLVNetRuleReconciler struct { + Reconciler *AsyncReconciler +} + +// +kubebuilder:rbac:groups=azure.microsoft.com,resources=postgresqlvnetrules,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=azure.microsoft.com,resources=postgresqlvnetrules/status,verbs=get;update;patch + +func (r *PostgreSQLVNetRuleReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { + return r.Reconciler.Reconcile(req, &azurev1alpha1.PostgreSQLVNetRule{}) +} + +func (r *PostgreSQLVNetRuleReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&azurev1alpha1.PostgreSQLVNetRule{}). + Complete(r) +} diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 2c143a82683..e64f5ce1e92 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -34,6 +34,7 @@ import ( mysqlDatabaseManager "github.com/Azure/azure-service-operator/pkg/resourcemanager/mysql/database" mysqlFirewallManager "github.com/Azure/azure-service-operator/pkg/resourcemanager/mysql/firewallrule" mysqlServerManager "github.com/Azure/azure-service-operator/pkg/resourcemanager/mysql/server" + mysqlvnetrule "github.com/Azure/azure-service-operator/pkg/resourcemanager/mysql/vnetrule" resourcemanagernic "github.com/Azure/azure-service-operator/pkg/resourcemanager/nic" resourcemanagerpip "github.com/Azure/azure-service-operator/pkg/resourcemanager/pip" resourcemanagerpsqldatabase "github.com/Azure/azure-service-operator/pkg/resourcemanager/psql/database" @@ -41,7 +42,6 @@ import ( resourcemanagerpsqlserver "github.com/Azure/azure-service-operator/pkg/resourcemanager/psql/server" resourcemanagerrediscaches "github.com/Azure/azure-service-operator/pkg/resourcemanager/rediscaches" resourcegroupsresourcemanager "github.com/Azure/azure-service-operator/pkg/resourcemanager/resourcegroups" - resourcemanagerstorages "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages" resourcemanagerblobcontainer "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages/blobcontainer" resourcemanagerstorageaccount "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages/storageaccount" "github.com/Azure/azure-service-operator/pkg/resourcemanager/vm" @@ -121,72 +121,10 @@ func setup() error { } secretClient := k8sSecrets.New(k8sManager.GetClient()) - - var appInsightsManager resourcemanagerappinsights.ApplicationInsightsManager - var apiMgmtManager resourcemanagerapimgmt.APIManager - var cosmosDbManager resourcemanagercosmosdb.CosmosDBManager - var resourceGroupManager resourcegroupsresourcemanager.ResourceGroupManager - var eventHubManagers resourcemanagereventhub.EventHubManagers - var storageManagers resourcemanagerstorages.StorageManagers - var eventhubNamespaceClient resourcemanagereventhub.EventHubNamespaceManager - var sqlServerManager resourcemanagersqlserver.SqlServerManager - var sqlDbManager resourcemanagersqldb.SqlDbManager - var sqlFirewallRuleManager resourcemanagersqlfirewallrule.SqlFirewallRuleManager - var sqlFailoverGroupManager resourcemanagersqlfailovergroup.SqlFailoverGroupManager - var sqlUserManager resourcemanagersqluser.SqlUserManager - var sqlActionManager resourcemanagersqlaction.SqlActionManager - var eventhubClient resourcemanagereventhub.EventHubManager - var psqlServerManager resourcemanagerpsqlserver.PostgreSQLServerManager - var psqlDatabaseManager resourcemanagerpsqldatabase.PostgreSQLDatabaseManager - var psqlFirewallRuleManager resourcemanagerpsqlfirewallrule.PostgreSQLFirewallRuleManager - var consumerGroupClient resourcemanagereventhub.ConsumerGroupManager - var sqlVNetRuleManager resourcemanagersqlvnetrule.SqlVNetRuleManager - - appInsightsManager = resourcemanagerappinsights.NewManager( - secretClient, - scheme.Scheme, - ) - cosmosDbManager = resourcemanagercosmosdb.NewAzureCosmosDBManager(secretClient) - apiMgmtManager = resourcemanagerapimgmt.NewManager() - resourceGroupManager = resourcegroupsresourcemanager.NewAzureResourceGroupManager() - eventHubManagers = resourcemanagereventhub.AzureEventHubManagers - storageManagers = resourcemanagerstorages.AzureStorageManagers - storageAccountManager := resourcemanagerstorageaccount.New() - blobContainerManager := resourcemanagerblobcontainer.New() + resourceGroupManager := resourcegroupsresourcemanager.NewAzureResourceGroupManager() keyVaultManager := resourcemanagerkeyvaults.NewAzureKeyVaultManager(k8sManager.GetScheme()) - keyVaultKeyManager := &resourcemanagerkeyvaults.KeyvaultKeyClient{ - KeyvaultClient: keyVaultManager, - } - - virtualNetworkManager := resourcemanagervnet.NewAzureVNetManager() - - eventhubClient = resourcemanagereventhub.NewEventhubClient(secretClient, scheme.Scheme) - psqlServerManager = resourcemanagerpsqlserver.NewPSQLServerClient(secretClient, k8sManager.GetScheme()) - psqlDatabaseManager = resourcemanagerpsqldatabase.NewPSQLDatabaseClient() - psqlFirewallRuleManager = resourcemanagerpsqlfirewallrule.NewPSQLFirewallRuleClient() - eventhubNamespaceClient = resourcemanagereventhub.NewEventHubNamespaceClient() - - sqlServerManager = resourcemanagersqlserver.NewAzureSqlServerManager( - secretClient, - scheme.Scheme, - ) - redisCacheManager := resourcemanagerrediscaches.NewAzureRedisCacheManager( - secretClient, - scheme.Scheme, - ) - sqlDbManager = resourcemanagersqldb.NewAzureSqlDbManager() - sqlFirewallRuleManager = resourcemanagersqlfirewallrule.NewAzureSqlFirewallRuleManager() - sqlVNetRuleManager = resourcemanagersqlvnetrule.NewAzureSqlVNetRuleManager() - sqlFailoverGroupManager = resourcemanagersqlfailovergroup.NewAzureSqlFailoverGroupManager( - secretClient, - scheme.Scheme, - ) - consumerGroupClient = resourcemanagereventhub.NewConsumerGroupClient() - sqlUserManager = resourcemanagersqluser.NewAzureSqlUserManager( - secretClient, - scheme.Scheme, - ) - sqlActionManager = resourcemanagersqlaction.NewAzureSqlActionManager(secretClient, scheme.Scheme) + eventhubClient := resourcemanagereventhub.NewEventhubClient(secretClient, scheme.Scheme) + consumerGroupClient := resourcemanagereventhub.NewConsumerGroupClient() timeout = time.Second * 780 @@ -208,8 +146,10 @@ func setup() error { err = (&KeyVaultKeyReconciler{ Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: keyVaultKeyManager, + Client: k8sManager.GetClient(), + AzureClient: &resourcemanagerkeyvaults.KeyvaultKeyClient{ + KeyvaultClient: keyVaultManager, + }, Telemetry: telemetry.InitializeTelemetryDefault( "KeyVaultKey", ctrl.Log.WithName("controllers").WithName("KeyVaultKey"), @@ -224,8 +164,11 @@ func setup() error { err = (&AppInsightsReconciler{ Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: appInsightsManager, + Client: k8sManager.GetClient(), + AzureClient: resourcemanagerappinsights.NewManager( + secretClient, + scheme.Scheme, + ), Telemetry: telemetry.InitializeTelemetryDefault( "AppInsights", ctrl.Log.WithName("controllers").WithName("AppInsights"), @@ -241,7 +184,7 @@ func setup() error { err = (&APIMAPIReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: apiMgmtManager, + AzureClient: resourcemanagerapimgmt.NewManager(), Telemetry: telemetry.InitializeTelemetryDefault( "ApiMgmt", ctrl.Log.WithName("controllers").WithName("ApiMgmt"), @@ -257,7 +200,7 @@ func setup() error { err = (&CosmosDBReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: cosmosDbManager, + AzureClient: resourcemanagercosmosdb.NewAzureCosmosDBManager(secretClient), Telemetry: telemetry.InitializeTelemetryDefault( "CosmosDB", ctrl.Log.WithName("controllers").WithName("CosmosDB"), @@ -304,8 +247,11 @@ func setup() error { err = (&RedisCacheReconciler{ Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: redisCacheManager, + Client: k8sManager.GetClient(), + AzureClient: resourcemanagerrediscaches.NewAzureRedisCacheManager( + secretClient, + scheme.Scheme, + ), Telemetry: telemetry.InitializeTelemetryDefault( "RedisCache", ctrl.Log.WithName("controllers").WithName("RedisCache"), @@ -321,7 +267,7 @@ func setup() error { err = (&EventhubNamespaceReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: eventhubNamespaceClient, + AzureClient: resourcemanagereventhub.NewEventHubNamespaceClient(), Telemetry: telemetry.InitializeTelemetryDefault( "EventhubNamespace", ctrl.Log.WithName("controllers").WithName("EventhubNamespace"), @@ -350,20 +296,13 @@ func setup() error { return err } - err = (&AzureDataLakeGen2FileSystemReconciler{ - Client: k8sManager.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("AzureDataLakeGen2FileSystem"), - Recorder: k8sManager.GetEventRecorderFor("AzureDataLakeGen2FileSystem-controller"), - FileSystemManager: storageManagers.FileSystem, - }).SetupWithManager(k8sManager) - if err != nil { - return err - } - err = (&AzureSqlServerReconciler{ Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: sqlServerManager, + Client: k8sManager.GetClient(), + AzureClient: resourcemanagersqlserver.NewAzureSqlServerManager( + secretClient, + scheme.Scheme, + ), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSqlServer", ctrl.Log.WithName("controllers").WithName("AzureSqlServer"), @@ -379,7 +318,7 @@ func setup() error { err = (&AzureSqlDatabaseReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: sqlDbManager, + AzureClient: resourcemanagersqldb.NewAzureSqlDbManager(), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSqlDb", ctrl.Log.WithName("controllers").WithName("AzureSqlDb"), @@ -395,7 +334,7 @@ func setup() error { err = (&AzureSqlFirewallRuleReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: sqlFirewallRuleManager, + AzureClient: resourcemanagersqlfirewallrule.NewAzureSqlFirewallRuleManager(), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSQLFirewallRuleOperator", ctrl.Log.WithName("controllers").WithName("AzureSQLFirewallRuleOperator"), @@ -411,7 +350,7 @@ func setup() error { err = (&AzureSQLVNetRuleReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: sqlVNetRuleManager, + AzureClient: resourcemanagersqlvnetrule.NewAzureSqlVNetRuleManager(), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSQLVNetRuleOperator", ctrl.Log.WithName("controllers").WithName("AzureSQLVNetRuleOperator"), @@ -426,8 +365,11 @@ func setup() error { err = (&AzureSqlFailoverGroupReconciler{ Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: sqlFailoverGroupManager, + Client: k8sManager.GetClient(), + AzureClient: resourcemanagersqlfailovergroup.NewAzureSqlFailoverGroupManager( + secretClient, + scheme.Scheme, + ), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSqlFailoverGroup", ctrl.Log.WithName("controllers").WithName("AzureSqlFailoverGroup"), @@ -442,8 +384,11 @@ func setup() error { err = (&AzureSQLUserReconciler{ Reconciler: &AsyncReconciler{ - Client: k8sManager.GetClient(), - AzureClient: sqlUserManager, + Client: k8sManager.GetClient(), + AzureClient: resourcemanagersqluser.NewAzureSqlUserManager( + secretClient, + scheme.Scheme, + ), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSqlUser", ctrl.Log.WithName("controllers").WithName("AzureSqlUser"), @@ -459,7 +404,7 @@ func setup() error { err = (&VirtualNetworkReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: virtualNetworkManager, + AzureClient: resourcemanagervnet.NewAzureVNetManager(), Telemetry: telemetry.InitializeTelemetryDefault( "VirtualNetwork", ctrl.Log.WithName("controllers").WithName("VirtualNetwork"), @@ -532,7 +477,7 @@ func setup() error { err = (&AzureSqlActionReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: sqlActionManager, + AzureClient: resourcemanagersqlaction.NewAzureSqlActionManager(secretClient, scheme.Scheme), Telemetry: telemetry.InitializeTelemetryDefault( "AzureSqlAction", ctrl.Log.WithName("controllers").WithName("AzureSqlAction"), @@ -548,7 +493,7 @@ func setup() error { err = (&BlobContainerReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: blobContainerManager, + AzureClient: resourcemanagerblobcontainer.New(), Telemetry: telemetry.InitializeTelemetryDefault( "BlobContainer", ctrl.Log.WithName("controllers").WithName("BlobContainer"), @@ -612,10 +557,26 @@ func setup() error { return err } + err = (&MySQLVNetRuleReconciler{ + Reconciler: &AsyncReconciler{ + Client: k8sManager.GetClient(), + AzureClient: mysqlvnetrule.NewMySQLVNetRuleClient(), + Telemetry: telemetry.InitializeTelemetryDefault( + "MySQLVNetRule", + ctrl.Log.WithName("controllers").WithName("MySQLVNetRule"), + ), + Recorder: k8sManager.GetEventRecorderFor("MySQLVNetRule-controller"), + Scheme: k8sManager.GetScheme(), + }, + }).SetupWithManager(k8sManager) + if err != nil { + return err + } + err = (&PostgreSQLServerReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: psqlServerManager, + AzureClient: resourcemanagerpsqlserver.NewPSQLServerClient(secretClient, k8sManager.GetScheme()), Telemetry: telemetry.InitializeTelemetryDefault( "PostgreSQLServer", ctrl.Log.WithName("controllers").WithName("PostgreSQLServer"), @@ -631,7 +592,7 @@ func setup() error { err = (&PostgreSQLDatabaseReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: psqlDatabaseManager, + AzureClient: resourcemanagerpsqldatabase.NewPSQLDatabaseClient(), Telemetry: telemetry.InitializeTelemetryDefault( "PostgreSQLDatabase", ctrl.Log.WithName("controllers").WithName("PostgreSQLDatabase"), @@ -647,7 +608,7 @@ func setup() error { err = (&PostgreSQLFirewallRuleReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: psqlFirewallRuleManager, + AzureClient: resourcemanagerpsqlfirewallrule.NewPSQLFirewallRuleClient(), Telemetry: telemetry.InitializeTelemetryDefault( "PostgreSQLFirewallRule", ctrl.Log.WithName("controllers").WithName("PostgreSQLFirewallRule"), @@ -663,7 +624,7 @@ func setup() error { err = (&StorageAccountReconciler{ Reconciler: &AsyncReconciler{ Client: k8sManager.GetClient(), - AzureClient: storageAccountManager, + AzureClient: resourcemanagerstorageaccount.New(), Telemetry: telemetry.InitializeTelemetryDefault( "StorageAccount", ctrl.Log.WithName("controllers").WithName("StorageAccount"), @@ -696,26 +657,18 @@ func setup() error { } tc = TestContext{ - k8sClient: k8sClient, - secretClient: secretClient, - resourceGroupName: resourceGroupName, - resourceGroupLocation: resourcegroupLocation, - keyvaultName: keyvaultName, - eventHubManagers: eventHubManagers, - eventhubClient: eventhubClient, - resourceGroupManager: resourceGroupManager, - redisCacheManager: redisCacheManager, - sqlServerManager: sqlServerManager, - sqlDbManager: sqlDbManager, - sqlFirewallRuleManager: sqlFirewallRuleManager, - sqlFailoverGroupManager: sqlFailoverGroupManager, - sqlUserManager: sqlUserManager, - storageManagers: storageManagers, - keyVaultManager: keyVaultManager, - timeout: timeout, - timeoutFast: time.Minute * 3, - retry: time.Second * 3, - consumerGroupClient: consumerGroupClient, + k8sClient: k8sClient, + secretClient: secretClient, + resourceGroupName: resourceGroupName, + resourceGroupLocation: resourcegroupLocation, + keyvaultName: keyvaultName, + eventhubClient: eventhubClient, + resourceGroupManager: resourceGroupManager, + keyVaultManager: keyVaultManager, + timeout: timeout, + timeoutFast: time.Minute * 3, + retry: time.Second * 3, + consumerGroupClient: consumerGroupClient, } log.Println("Creating KV:", keyvaultName) diff --git a/controllers/virtualnetwork_controller_test.go b/controllers/virtualnetwork_controller_test.go index 7942d7767e3..121e53f45b9 100644 --- a/controllers/virtualnetwork_controller_test.go +++ b/controllers/virtualnetwork_controller_test.go @@ -10,9 +10,73 @@ import ( "testing" azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" + "github.com/Azure/azure-service-operator/pkg/errhelp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +func TestVirtualNetworkNoResourceGroup(t *testing.T) { + defer PanicRecover(t) + ctx := context.Background() + + VNetName := GenerateTestResourceNameWithRandom("vnet", 10) + subnetName := "subnet-test" + VNetSubNetInstance := azurev1alpha1.VNetSubnets{ + SubnetName: subnetName, + SubnetAddressPrefix: "110.1.0.0/16", + } + + // Create a VNET + VNetInstance := &azurev1alpha1.VirtualNetwork{ + ObjectMeta: metav1.ObjectMeta{ + Name: VNetName, + Namespace: "default", + }, + Spec: azurev1alpha1.VirtualNetworkSpec{ + Location: tc.resourceGroupLocation, + ResourceGroup: GenerateTestResourceNameWithRandom("", 10), + AddressSpace: "110.0.0.0/8", + Subnets: []azurev1alpha1.VNetSubnets{VNetSubNetInstance}, + }, + } + + EnsureInstanceWithResult(ctx, t, tc, VNetInstance, errhelp.ResourceGroupNotFoundErrorCode, false) + + EnsureDelete(ctx, t, tc, VNetInstance) + +} + +func TestVirtualNetworkBadServiceEndpoint(t *testing.T) { + defer PanicRecover(t) + ctx := context.Background() + + VNetName := GenerateTestResourceNameWithRandom("vnet", 10) + subnetName := "subnet-test" + VNetSubNetInstance := azurev1alpha1.VNetSubnets{ + SubnetName: subnetName, + SubnetAddressPrefix: "110.1.0.0/16", + ServiceEndpoints: []string{"Microsoft.Bananas"}, + } + + // Create a VNET + VNetInstance := &azurev1alpha1.VirtualNetwork{ + ObjectMeta: metav1.ObjectMeta{ + Name: VNetName, + Namespace: "default", + }, + Spec: azurev1alpha1.VirtualNetworkSpec{ + Location: tc.resourceGroupLocation, + ResourceGroup: tc.resourceGroupName, + AddressSpace: "110.0.0.0/8", + Subnets: []azurev1alpha1.VNetSubnets{VNetSubNetInstance}, + }, + } + + EnsureInstanceWithResult(ctx, t, tc, VNetInstance, errhelp.SubnetHasServiceEndpointWithInvalidServiceName, false) + + EnsureDelete(ctx, t, tc, VNetInstance) + +} + func TestVirtualNetworkHappyPath(t *testing.T) { defer PanicRecover(t) ctx := context.Background() @@ -22,6 +86,7 @@ func TestVirtualNetworkHappyPath(t *testing.T) { VNetSubNetInstance := azurev1alpha1.VNetSubnets{ SubnetName: subnetName, SubnetAddressPrefix: "110.1.0.0/16", + ServiceEndpoints: []string{"Microsoft.Storage"}, } // Create a VNET diff --git a/devops/azure-pipelines.yaml b/devops/azure-pipelines.yaml index 189de44353a..689f19908f7 100644 --- a/devops/azure-pipelines.yaml +++ b/devops/azure-pipelines.yaml @@ -111,25 +111,25 @@ steps: kind create cluster export KUBECONFIG=$(kind get kubeconfig-path --name="kind") kubectl cluster-info - kubectl create namespace cert-manager - kubectl label namespace cert-manager cert-manager.io/disable-validation=true - kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.12.0/cert-manager.yaml - kubectl create namespace azureoperator-system - kubectl --namespace azureoperator-system \ - create secret generic azureoperatorsettings \ - --from-literal=AZURE_CLIENT_ID=${AZURE_CLIENT_ID} \ - --from-literal=AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET} \ - --from-literal=AZURE_SUBSCRIPTION_ID=${AZURE_SUBSCRIPTION_ID} \ - --from-literal=AZURE_TENANT_ID=${AZURE_TENANT_ID} + # kubectl create namespace cert-manager + # kubectl label namespace cert-manager cert-manager.io/disable-validation=true + # kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.12.0/cert-manager.yaml + # kubectl create namespace azureoperator-system + # kubectl --namespace azureoperator-system \ + # create secret generic azureoperatorsettings \ + # --from-literal=AZURE_CLIENT_ID=${AZURE_CLIENT_ID} \ + # --from-literal=AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET} \ + # --from-literal=AZURE_SUBSCRIPTION_ID=${AZURE_SUBSCRIPTION_ID} \ + # --from-literal=AZURE_TENANT_ID=${AZURE_TENANT_ID} #create image and load it into cluster - IMG="docker.io/controllertest:1" make -f Makefile.legacy docker-build - kind load docker-image docker.io/controllertest:1 --loglevel "trace" + # IMG="docker.io/controllertest:1" make docker-build + # kind load docker-image docker.io/controllertest:1 --loglevel "trace" make -f Makefile.legacy install kubectl get namespaces - kubectl -n cert-manager rollout status deployment.v1.apps/cert-manager - kubectl get pods --namespace cert-manager - echo "all the pods should be running" - make -f Makefile.legacy deploy + # kubectl -n cert-manager rollout status deployment.v1.apps/cert-manager + # kubectl get pods --namespace cert-manager + # echo "all the pods should be running" + #make deploy make -f Makefile.legacy test-existing-controllers continueOnError: 'false' displayName: 'Set kind cluster and Run int tests' diff --git a/docs/development.md b/docs/development.md index 805e67cbe70..139b150ca9f 100644 --- a/docs/development.md +++ b/docs/development.md @@ -452,6 +452,19 @@ go build -o bin/manager main.go If you make changes to the operator and want to update the deployment without recreating the cluster (when testing locally), you can use the `make update` to update your Azure Operator pod. If you need to rebuild the docker image without cache, use `make ARGS="--no-cache" update` +12. Update the Helm Chart to include the new CRD. + Run: + ``` + make helm-chart-manifests + make delete-helm-gen-manifests + ``` + + This will generate the manifests into the Helm Chart directory, and repackage them into a new Helm Chart tar.gz file. Add the newly modified files to the PR, which should be the following: + ``` + charts/azure-service-operator-0.1.0.tgz + charts/index.yaml + ``` + **Notes:** - Run `make manifests` if you find the property you add doesn't work. diff --git a/docs/storage/azuredatalakegen2.md b/docs/storage/azuredatalakegen2.md deleted file mode 100644 index 09eed59c30a..00000000000 --- a/docs/storage/azuredatalakegen2.md +++ /dev/null @@ -1,38 +0,0 @@ -# Azure Data Lake Gen2 Operator - -## Resources Supported - -The Azure Data Lake Gen2 operator can be used to provision the following resources - -1. Azure Data Lake Gen2 enabled storage account - Deploys a data lake gen2 enabled storage account using the storage operator -2. Azure Data Lake Gen2 Filesystem - Deploys a filesystem inside of a data lake gen2 enabled storage account - -### Azure Data Lake Gen 2 Enabled Storage Account - -A sample YAML for the Data Lake Gen2 FileSystem is [here](/config/samples/azure_v1alpha1_azuredatalakegen2storage.yaml) - -Important Values: - -- Kind: the Custom Resource Definition (CRD) name -- Metadata.Name: the name of the data lake enabled storage account that will be created -- Spec.Location: Azure region where you want to create the data lake enabled storage account -- Spec.ResourceGroup: Name of the resource group under which you want to create the data lake enabled storage account -- Spec.Kind: The kind of storage account that you want to create. This value must be `StorageV2` in order for it to be a data lake -- Spec.AccessTier - The access tier for the storage account. Choose "Hot" access tier for frequently accessed data and "Cool" for infrequently accessed data -- Spec.SupportsHttpsTrafficOnly - When "enabled", requires connection requests to the storage account to be only over HTTPS -- Spec.DataLakeEnabled: If set to `true`, the storage account will have hierarchical namespace enabled and will, therefore, be a data lake enabled storage account - -### Azure Data Lake Gen 2 FileSystem - -A sample YAML for the Data Lake Gen2 FileSystem is [here](/config/samples/azure_v1alpha1_azuredatalakegen2filesystem.yaml) - -Important Values: - -- Kind: the Custom Resource Definition (CRD) name -- Metadata.Name: the name of the data lake enabled storage account that will be created -- Spec.StorageAccountName: Name of the data lake enabled storage account in which you would like to create the filesystem -- Spec.ResourceGroup: Name of the resource group under which the storage account lives - -## Deploy, view and delete resources - -You can follow the steps [here](/docs/customresource.md) to deploy, view and delete resources. diff --git a/main.go b/main.go index a46481c13c1..3edc9ea740c 100644 --- a/main.go +++ b/main.go @@ -34,9 +34,9 @@ import ( psqldatabase "github.com/Azure/azure-service-operator/pkg/resourcemanager/psql/database" psqlfirewallrule "github.com/Azure/azure-service-operator/pkg/resourcemanager/psql/firewallrule" psqlserver "github.com/Azure/azure-service-operator/pkg/resourcemanager/psql/server" + psqlvnetrule "github.com/Azure/azure-service-operator/pkg/resourcemanager/psql/vnetrule" resourcemanagerrediscache "github.com/Azure/azure-service-operator/pkg/resourcemanager/rediscaches" resourcemanagerresourcegroup "github.com/Azure/azure-service-operator/pkg/resourcemanager/resourcegroups" - resourcemanagerstorage "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages" blobContainerManager "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages/blobcontainer" storageaccountManager "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages/storageaccount" vm "github.com/Azure/azure-service-operator/pkg/resourcemanager/vm" @@ -131,7 +131,6 @@ func main() { cosmosDBClient := resourcemanagercosmosdb.NewAzureCosmosDBManager( secretClient, ) - storageManagers := resourcemanagerstorage.AzureStorageManagers keyVaultManager := resourcemanagerkeyvault.NewAzureKeyVaultManager(mgr.GetScheme()) keyVaultKeyManager := &resourcemanagerkeyvault.KeyvaultKeyClient{ KeyvaultClient: keyVaultManager, @@ -421,16 +420,6 @@ func main() { os.Exit(1) } - if err = (&controllers.AzureDataLakeGen2FileSystemReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("AzureDataLakeGen2FileSystem"), - Recorder: mgr.GetEventRecorderFor("AzureDataLakeGen2FileSystem-controller"), - FileSystemManager: storageManagers.FileSystem, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "AzureDataLakeGen2FileSystem") - os.Exit(1) - } - if err = (&controllers.AppInsightsReconciler{ Reconciler: &controllers.AsyncReconciler{ Client: mgr.GetClient(), @@ -645,6 +634,7 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "NetworkInterface") os.Exit(1) } + if err = (&controllers.MySQLVNetRuleReconciler{ Reconciler: &controllers.AsyncReconciler{ Client: mgr.GetClient(), @@ -680,6 +670,22 @@ func main() { os.Exit(1) } + if err = (&controllers.PostgreSQLVNetRuleReconciler{ + Reconciler: &controllers.AsyncReconciler{ + Client: mgr.GetClient(), + AzureClient: psqlvnetrule.NewPostgreSQLVNetRuleClient(), + Telemetry: telemetry.InitializeTelemetryDefault( + "PostgreSQLVNetRule", + ctrl.Log.WithName("controllers").WithName("PostgreSQLVNetRule"), + ), + Recorder: mgr.GetEventRecorderFor("PostgreSQLVNetRule-controller"), + Scheme: scheme, + }, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "PostgreSQLVNetRule") + os.Exit(1) + } + // +kubebuilder:scaffold:builder setupLog.Info("starting manager") diff --git a/pkg/errhelp/errors.go b/pkg/errhelp/errors.go index e1f0f469859..ecdd0beef37 100644 --- a/pkg/errhelp/errors.go +++ b/pkg/errhelp/errors.go @@ -15,50 +15,54 @@ import ( ) const ( - AccountNameInvalid = "AccountNameInvalid" - AlreadyExists = "AlreadyExists" - AsyncOpIncompleteError = "AsyncOpIncomplete" - BadRequest = "BadRequest" - CannotParseError = "CannotParseError" - ConflictingServerOperation = "ConflictingServerOperation" - ContainerOperationFailure = "ContainerOperationFailure" - CreationPending = "CreationPending" - FailoverGroupBusy = "FailoverGroupBusy" - Forbidden = "Forbidden" - InvalidAccessPolicy = "InvalidAccessPolicy" - InvalidCIDRNotation = "InvalidCIDRNotation" - InvalidFailoverGroupRegion = "InvalidFailoverGroupRegion" - InvalidParameters = "InvalidParameters" - InvalidRequestFormat = "InvalidRequestFormat" - InvalidResourceLocation = "InvalidResourceLocation" - InvalidServerName = "InvalidServerName" - InvalidResourceReference = "InvalidResourceReference" - KeyNotFound = "KeyNotFound" - LocationNotAvailableForResourceType = "LocationNotAvailableForResourceType" - ProvisioningDisabled = "ProvisioningDisabled" - NetcfgInvalidIPAddressPrefix = "NetcfgInvalidIPAddressPrefix" - NetcfgInvalidSubnet = "NetcfgInvalidSubnet" - NetcfgInvalidVirtualNetworkSite = "NetcfgInvalidVirtualNetworkSite" - NotFoundErrorCode = "NotFound" - NoSuchHost = "no such host" - ParentNotFoundErrorCode = "ParentResourceNotFound" - PreconditionFailed = "PreconditionFailed" - QuotaExceeded = "QuotaExceeded" - ResourceGroupNotFoundErrorCode = "ResourceGroupNotFound" - RegionDoesNotAllowProvisioning = "RegionDoesNotAllowProvisioning" - ResourceNotFound = "ResourceNotFound" - RequestConflictError = "Conflict" - ValidationError = "ValidationError" - SubscriptionDoesNotHaveServer = "SubscriptionDoesNotHaveServer" - NotSupported = "NotSupported" - SecretNotFound = "SecretNotFound" - RequestDisallowedByPolicy = "RequestDisallowedByPolicy" - ServiceBusy = "ServiceBusy" - NameNotAvailable = "NameNotAvailable" - PublicIPIdleTimeoutIsOutOfRange = "PublicIPIdleTimeoutIsOutOfRange" - InvalidRequestContent = "InvalidRequestContent" - InternalServerError = "InternalServerError" - NetworkAclsValidationFailure = "NetworkAclsValidationFailure" + AccountNameInvalid = "AccountNameInvalid" + AlreadyExists = "AlreadyExists" + AsyncOpIncompleteError = "AsyncOpIncomplete" + BadRequest = "BadRequest" + CannotParseError = "CannotParseError" + ConflictingServerOperation = "ConflictingServerOperation" + ContainerOperationFailure = "ContainerOperationFailure" + CreationPending = "CreationPending" + FailoverGroupBusy = "FailoverGroupBusy" + Forbidden = "Forbidden" + InvalidAccessPolicy = "InvalidAccessPolicy" + InvalidCIDRNotation = "InvalidCIDRNotation" + InvalidFailoverGroupRegion = "InvalidFailoverGroupRegion" + InvalidParameters = "InvalidParameters" + InvalidRequestFormat = "InvalidRequestFormat" + InvalidResourceLocation = "InvalidResourceLocation" + InvalidServerName = "InvalidServerName" + InvalidResourceReference = "InvalidResourceReference" + KeyNotFound = "KeyNotFound" + LocationNotAvailableForResourceType = "LocationNotAvailableForResourceType" + ProvisioningDisabled = "ProvisioningDisabled" + NetcfgInvalidIPAddressPrefix = "NetcfgInvalidIPAddressPrefix" + NetcfgInvalidSubnet = "NetcfgInvalidSubnet" + NetcfgInvalidVirtualNetworkSite = "NetcfgInvalidVirtualNetworkSite" + NotFoundErrorCode = "NotFound" + NoSuchHost = "no such host" + ParentNotFoundErrorCode = "ParentResourceNotFound" + PreconditionFailed = "PreconditionFailed" + QuotaExceeded = "QuotaExceeded" + ResourceGroupNotFoundErrorCode = "ResourceGroupNotFound" + RegionDoesNotAllowProvisioning = "RegionDoesNotAllowProvisioning" + ResourceNotFound = "ResourceNotFound" + RequestConflictError = "Conflict" + ValidationError = "ValidationError" + SubscriptionDoesNotHaveServer = "SubscriptionDoesNotHaveServer" + NotSupported = "NotSupported" + SecretNotFound = "SecretNotFound" + RequestDisallowedByPolicy = "RequestDisallowedByPolicy" + ServiceBusy = "ServiceBusy" + NameNotAvailable = "NameNotAvailable" + PublicIPIdleTimeoutIsOutOfRange = "PublicIPIdleTimeoutIsOutOfRange" + InvalidRequestContent = "InvalidRequestContent" + InternalServerError = "InternalServerError" + NetworkAclsValidationFailure = "NetworkAclsValidationFailure" + SubnetHasServiceEndpointWithInvalidServiceName = "SubnetHasServiceEndpointWithInvalidServiceName" + InvalidAddressPrefixFormat = "InvalidAddressPrefixFormat" + FeatureNotSupportedForEdition = "FeatureNotSupportedForEdition" + VirtualNetworkRuleBadRequest = "VirtualNetworkRuleBadRequest" ) func NewAzureError(err error) error { diff --git a/pkg/helpers/stringhelper.go b/pkg/helpers/stringhelper.go index 6c269e260c6..e223f68948e 100644 --- a/pkg/helpers/stringhelper.go +++ b/pkg/helpers/stringhelper.go @@ -15,7 +15,6 @@ import ( "unicode" "github.com/sethvargo/go-password/password" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( @@ -88,11 +87,6 @@ func RandomString(length int) string { return randomStringWithCharset(length, lowerAlphaChars) } -// IsBeingDeleted returns true if the current object is being deleted from the API server. -func IsBeingDeleted(o metav1.Object) bool { - return !o.GetDeletionTimestamp().IsZero() -} - // GenerateRandomUsername - helper function to generate random username for sql server func GenerateRandomUsername(n int) string { diff --git a/pkg/resourcemanager/apim/apimgmt/apimgmt.go b/pkg/resourcemanager/apim/apimgmt/apimgmt.go index 24743af44e5..057be8c7163 100644 --- a/pkg/resourcemanager/apim/apimgmt/apimgmt.go +++ b/pkg/resourcemanager/apim/apimgmt/apimgmt.go @@ -6,6 +6,7 @@ package apimgmt import ( "context" "fmt" + "net/http" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -23,15 +24,11 @@ import ( ) // Manager represents an API Management type -type Manager struct { - APIClient apimanagement.APIClient -} +type Manager struct{} // NewManager returns an API Manager type func NewManager() *Manager { - return &Manager{ - APIClient: apimshared.GetAPIMClient(), - } + return &Manager{} } // CreateAPI creates an API within an API management service @@ -69,28 +66,45 @@ func (m *Manager) CreateAPI( return apimanagement.APIContract{}, err } + apiClient, err := apimshared.GetAPIMClient() + if err != nil { + return apimanagement.APIContract{}, err + } + // Submit the ARM request - future, err := m.APIClient.CreateOrUpdate(ctx, resourceGroupName, *svc.Name, apiID, params, eTag) + future, err := apiClient.CreateOrUpdate(ctx, resourceGroupName, *svc.Name, apiID, params, eTag) if err != nil { return apimanagement.APIContract{}, err } - return future.Result(m.APIClient) + return future.Result(apiClient) } // DeleteAPI deletes an API within an API management service func (m *Manager) DeleteAPI(ctx context.Context, resourceGroupName string, apiServiceName string, apiID string, eTag string, deleteRevisions bool) (autorest.Response, error) { - result, err := m.APIClient.Get(ctx, resourceGroupName, apiServiceName, apiID) + apiClient, err := apimshared.GetAPIMClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + result, err := apiClient.Get(ctx, resourceGroupName, apiServiceName, apiID) if err == nil { - return m.APIClient.Delete(ctx, resourceGroupName, apiServiceName, apiID, eTag, &deleteRevisions) + return apiClient.Delete(ctx, resourceGroupName, apiServiceName, apiID, eTag, &deleteRevisions) } return result.Response, err } // GetAPI fetches an API within an API management service func (m *Manager) GetAPI(ctx context.Context, resourceGroupName string, apiServiceName string, apiID string) (apimanagement.APIContract, error) { - contract, err := m.APIClient.Get(ctx, resourceGroupName, apiServiceName, apiID) + apiClient, err := apimshared.GetAPIMClient() + if err != nil { + return apimanagement.APIContract{}, err + } + contract, err := apiClient.Get(ctx, resourceGroupName, apiServiceName, apiID) return contract, err } diff --git a/pkg/resourcemanager/apim/apimservice/reconcile.go b/pkg/resourcemanager/apim/apimservice/reconcile.go index 8f226c7bd70..80f04019817 100644 --- a/pkg/resourcemanager/apim/apimservice/reconcile.go +++ b/pkg/resourcemanager/apim/apimservice/reconcile.go @@ -192,24 +192,33 @@ func (g *AzureAPIMgmtServiceManager) Delete(ctx context.Context, obj runtime.Obj resourceGroupName := instance.Spec.ResourceGroup resourceName := instance.ObjectMeta.Name - catch := []string{ - errhelp.ResourceGroupNotFoundErrorCode, - errhelp.ParentNotFoundErrorCode, - errhelp.NotFoundErrorCode, - } - requeue := []string{ - errhelp.AsyncOpIncompleteError, - } - _, err = g.DeleteAPIMgmtSvc(ctx, resourceGroupName, resourceName) if err != nil { azerr := errhelp.NewAzureErrorAzureError(err) - if helpers.ContainsString(catch, azerr.Type) { + + alreadyDeletedErrors := []string{ + errhelp.ResourceGroupNotFoundErrorCode, + errhelp.ParentNotFoundErrorCode, + errhelp.NotFoundErrorCode, + } + requeue := []string{ + errhelp.AsyncOpIncompleteError, + } + + // already deleted so exit successfully + if helpers.ContainsString(alreadyDeletedErrors, azerr.Type) { return false, nil - } else if helpers.ContainsString(requeue, azerr.Type) { + } + + // requeue the delete to try again + instance.Status.Message = "Deletion is not complete" + errorStr := err.Error() + if helpers.ContainsString(requeue, azerr.Type) || + strings.Contains(errorStr, "FailedDelete") || + strings.Contains(errorStr, "Failure sending request: StatusCode=0") { return true, nil } - return true, fmt.Errorf("API Mgmt Svc delete error %v", err) + return true, fmt.Errorf("API Mgmt Svc delete error: %v", err) } return false, nil diff --git a/pkg/resourcemanager/apim/apimshared/common.go b/pkg/resourcemanager/apim/apimshared/common.go index af4166028bb..1e334292364 100644 --- a/pkg/resourcemanager/apim/apimshared/common.go +++ b/pkg/resourcemanager/apim/apimshared/common.go @@ -184,16 +184,15 @@ func GetAppInstanceIDByName(ctx context.Context, resourceGroup string, resourceN } // GetAPIMClient returns a pointer to an API Management client -func GetAPIMClient() apim.APIClient { +func GetAPIMClient() (apim.APIClient, error) { apimClient := apim.NewAPIClient(config.SubscriptionID()) a, err := iam.GetResourceManagementAuthorizer() - apimClient.Authorizer = a - apimClient.AddToUserAgent(config.UserAgent()) - if err != nil { - panic(err) + return apim.APIClient{}, err } + apimClient.Authorizer = a + apimClient.AddToUserAgent(config.UserAgent()) - return apimClient + return apimClient, nil } diff --git a/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb.go b/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb.go index 2f59d0c6ee4..a3b28000840 100644 --- a/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb.go +++ b/pkg/resourcemanager/azuresql/azuresqldb/azuresqldb.go @@ -23,7 +23,10 @@ func NewAzureSqlDbManager() *AzureSqlDbManager { // GetServer returns a SQL server func (_ *AzureSqlDbManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return sql.Server{}, err + } return serversClient.Get( ctx, diff --git a/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup.go b/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup.go index 45e4cf92fdd..2b9bcf7b5df 100644 --- a/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup.go +++ b/pkg/resourcemanager/azuresql/azuresqlfailovergroup/azuresqlfailovergroup.go @@ -32,7 +32,10 @@ func NewAzureSqlFailoverGroupManager(secretClient secrets.SecretClient, scheme * // GetServer returns a SQL server func (f *AzureSqlFailoverGroupManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return sql.Server{}, err + } return serversClient.Get( ctx, @@ -59,7 +62,10 @@ func (f *AzureSqlFailoverGroupManager) GetDB(ctx context.Context, resourceGroupN // GetFailoverGroup retrieves a failover group func (f *AzureSqlFailoverGroupManager) GetFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failovergroupname string) (sql.FailoverGroup, error) { - failoverGroupsClient := azuresqlshared.GetGoFailoverGroupsClient() + failoverGroupsClient, err := azuresqlshared.GetGoFailoverGroupsClient() + if err != nil { + return sql.FailoverGroup{}, err + } return failoverGroupsClient.Get( ctx, @@ -71,12 +77,12 @@ func (f *AzureSqlFailoverGroupManager) GetFailoverGroup(ctx context.Context, res // DeleteFailoverGroup deletes a failover group func (sdk *AzureSqlFailoverGroupManager) DeleteFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failoverGroupName string) (result autorest.Response, err error) { - result = autorest.Response{ Response: &http.Response{ StatusCode: 200, }, } + // check to see if the server exists, if it doesn't then short-circuit _, err = sdk.GetServer(ctx, resourceGroupName, serverName) if err != nil { @@ -87,7 +93,12 @@ func (sdk *AzureSqlFailoverGroupManager) DeleteFailoverGroup(ctx context.Context if err != nil { return result, nil } - failoverGroupsClient := azuresqlshared.GetGoFailoverGroupsClient() + + failoverGroupsClient, err := azuresqlshared.GetGoFailoverGroupsClient() + if err != nil { + return result, err + } + future, err := failoverGroupsClient.Delete( ctx, resourceGroupName, @@ -103,7 +114,10 @@ func (sdk *AzureSqlFailoverGroupManager) DeleteFailoverGroup(ctx context.Context // CreateOrUpdateFailoverGroup creates a failover group func (sdk *AzureSqlFailoverGroupManager) CreateOrUpdateFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failovergroupname string, properties azuresqlshared.SQLFailoverGroupProperties) (result sql.FailoverGroupsCreateOrUpdateFuture, err error) { - failoverGroupsClient := azuresqlshared.GetGoFailoverGroupsClient() + failoverGroupsClient, err := azuresqlshared.GetGoFailoverGroupsClient() + if err != nil { + return sql.FailoverGroupsCreateOrUpdateFuture{}, err + } // Construct a PartnerInfo object from the server name // Get resource ID from the servername to use diff --git a/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule.go b/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule.go index 4f4a48cb49f..b6a33db00ce 100644 --- a/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule.go +++ b/pkg/resourcemanager/azuresql/azuresqlfirewallrule/azuresqlfirewallrule.go @@ -21,7 +21,10 @@ func NewAzureSqlFirewallRuleManager() *AzureSqlFirewallRuleManager { // GetServer returns a SQL server func (_ *AzureSqlFirewallRuleManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return sql.Server{}, err + } return serversClient.Get( ctx, @@ -32,7 +35,10 @@ func (_ *AzureSqlFirewallRuleManager) GetServer(ctx context.Context, resourceGro // GetSQLFirewallRule returns a firewall rule func (_ *AzureSqlFirewallRuleManager) GetSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (result sql.FirewallRule, err error) { - firewallClient := azuresqlshared.GetGoFirewallClient() + firewallClient, err := azuresqlshared.GetGoFirewallClient() + if err != nil { + return sql.FirewallRule{}, err + } return firewallClient.Get( ctx, @@ -57,7 +63,11 @@ func (sdk *AzureSqlFirewallRuleManager) DeleteSQLFirewallRule(ctx context.Contex return nil } - firewallClient := azuresqlshared.GetGoFirewallClient() + firewallClient, err := azuresqlshared.GetGoFirewallClient() + if err != nil { + return err + } + _, err = firewallClient.Delete( ctx, resourceGroupName, @@ -79,7 +89,11 @@ func (sdk *AzureSqlFirewallRuleManager) CreateOrUpdateSQLFirewallRule(ctx contex return false, err } - firewallClient := azuresqlshared.GetGoFirewallClient() + firewallClient, err := azuresqlshared.GetGoFirewallClient() + if err != nil { + return false, err + } + _, err = firewallClient.CreateOrUpdate( ctx, resourceGroupName, diff --git a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver.go b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver.go index ba9d6504865..22a5b116b6f 100644 --- a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver.go +++ b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver.go @@ -44,7 +44,11 @@ func (sdk *AzureSqlServerManager) DeleteSQLServer(ctx context.Context, resourceG return result, nil } - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return result, err + } + future, err := serversClient.Delete( ctx, resourceGroupName, @@ -59,7 +63,10 @@ func (sdk *AzureSqlServerManager) DeleteSQLServer(ctx context.Context, resourceG // GetServer returns a SQL server func (_ *AzureSqlServerManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return sql.Server{}, err + } return serversClient.Get( ctx, @@ -70,7 +77,11 @@ func (_ *AzureSqlServerManager) GetServer(ctx context.Context, resourceGroupName // CreateOrUpdateSQLServer creates a SQL server in Azure func (_ *AzureSqlServerManager) CreateOrUpdateSQLServer(ctx context.Context, resourceGroupName string, location string, serverName string, tags map[string]*string, properties azuresqlshared.SQLServerProperties, forceUpdate bool) (pollingURL string, result sql.Server, err error) { - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return "", sql.Server{}, err + } + serverProp := azuresqlshared.SQLServerPropertiesToServer(properties) if forceUpdate == false { @@ -105,7 +116,10 @@ func (_ *AzureSqlServerManager) CreateOrUpdateSQLServer(ctx context.Context, res } func CheckNameAvailability(ctx context.Context, serverName string) (result sql.CheckNameAvailabilityResponse, err error) { - serversClient := azuresqlshared.GetGoServersClient() + serversClient, err := azuresqlshared.GetGoServersClient() + if err != nil { + return sql.CheckNameAvailabilityResponse{}, err + } response, err := serversClient.CheckNameAvailability( ctx, diff --git a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go index 8e76fb24ab9..a1506bfed50 100644 --- a/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go +++ b/pkg/resourcemanager/azuresql/azuresqlserver/azuresqlserver_reconcile.go @@ -200,11 +200,13 @@ func (s *AzureSqlServerManager) Ensure(ctx context.Context, obj runtime.Object, case errhelp.LocationNotAvailableForResourceType, errhelp.RequestDisallowedByPolicy, errhelp.RegionDoesNotAllowProvisioning, + errhelp.InvalidResourceLocation, errhelp.QuotaExceeded: instance.Status.Message = "Unable to provision Azure SQL Server due to error: " + errhelp.StripErrorIDs(err) instance.Status.Provisioning = false instance.Status.Provisioned = false + instance.Status.FailedProvisioning = true return true, nil } diff --git a/pkg/resourcemanager/azuresql/azuresqlshared/getgoclients.go b/pkg/resourcemanager/azuresql/azuresqlshared/getgoclients.go index 2c960669c7c..f5a126891ba 100644 --- a/pkg/resourcemanager/azuresql/azuresqlshared/getgoclients.go +++ b/pkg/resourcemanager/azuresql/azuresqlshared/getgoclients.go @@ -23,47 +23,61 @@ func GetGoDbClient() (sql.DatabasesClient, error) { } // GetGoServersClient retrieves a ServersClient -func GetGoServersClient() sql.ServersClient { +func GetGoServersClient() (sql.ServersClient, error) { serversClient := sql.NewServersClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - - a, _ := iam.GetResourceManagementAuthorizer() + a, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return sql.ServersClient{}, err + } serversClient.Authorizer = a serversClient.AddToUserAgent(config.UserAgent()) - return serversClient + return serversClient, nil } // GetGoFailoverGroupsClient retrieves a FailoverGroupsClient -func GetGoFailoverGroupsClient() sql.FailoverGroupsClient { +func GetGoFailoverGroupsClient() (sql.FailoverGroupsClient, error) { failoverGroupsClient := sql.NewFailoverGroupsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - a, _ := iam.GetResourceManagementAuthorizer() + a, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return sql.FailoverGroupsClient{}, err + } failoverGroupsClient.Authorizer = a failoverGroupsClient.AddToUserAgent(config.UserAgent()) - return failoverGroupsClient + return failoverGroupsClient, nil } // GetGoFirewallClient retrieves a FirewallRulesClient -func GetGoFirewallClient() sql.FirewallRulesClient { +func GetGoFirewallClient() (sql.FirewallRulesClient, error) { firewallClient := sql.NewFirewallRulesClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - a, _ := iam.GetResourceManagementAuthorizer() + a, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return sql.FirewallRulesClient{}, err + } firewallClient.Authorizer = a firewallClient.AddToUserAgent(config.UserAgent()) - return firewallClient + return firewallClient, nil } // GetGoVNetRulesClient retrieves a VirtualNetworkRulesClient -func GetGoVNetRulesClient() sql.VirtualNetworkRulesClient { +func GetGoVNetRulesClient() (sql.VirtualNetworkRulesClient, error) { VNetRulesClient := sql.NewVirtualNetworkRulesClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - a, _ := iam.GetResourceManagementAuthorizer() + a, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return sql.VirtualNetworkRulesClient{}, err + } VNetRulesClient.Authorizer = a VNetRulesClient.AddToUserAgent(config.UserAgent()) - return VNetRulesClient + return VNetRulesClient, nil } // GetNetworkSubnetClient retrieves a Subnetclient -func GetGoNetworkSubnetClient() network.SubnetsClient { +func GetGoNetworkSubnetClient() (network.SubnetsClient, error) { SubnetsClient := network.NewSubnetsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - a, _ := iam.GetResourceManagementAuthorizer() + a, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return network.SubnetsClient{}, err + } SubnetsClient.Authorizer = a SubnetsClient.AddToUserAgent(config.UserAgent()) - return SubnetsClient + return SubnetsClient, nil } diff --git a/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule.go b/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule.go index e70f17ff865..dc09207f03e 100644 --- a/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule.go +++ b/pkg/resourcemanager/azuresql/azuresqlvnetrule/azuresqlvnetrule.go @@ -19,7 +19,10 @@ func NewAzureSqlVNetRuleManager() *AzureSqlVNetRuleManager { // GetSQLVNetRule returns a VNet rule func (vr *AzureSqlVNetRuleManager) GetSQLVNetRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (result sql.VirtualNetworkRule, err error) { - VNetRulesClient := azuresqlshared.GetGoVNetRulesClient() + VNetRulesClient, err := azuresqlshared.GetGoVNetRulesClient() + if err != nil { + return sql.VirtualNetworkRule{}, err + } return VNetRulesClient.Get( ctx, @@ -38,7 +41,11 @@ func (vr *AzureSqlVNetRuleManager) DeleteSQLVNetRule(ctx context.Context, resour return nil } - VNetRulesClient := azuresqlshared.GetGoVNetRulesClient() + VNetRulesClient, err := azuresqlshared.GetGoVNetRulesClient() + if err != nil { + return err + } + _, err = VNetRulesClient.Delete( ctx, resourceGroupName, @@ -53,8 +60,15 @@ func (vr *AzureSqlVNetRuleManager) DeleteSQLVNetRule(ctx context.Context, resour // based on code from: https://godoc.org/github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql#VirtualNetworkRulesClient.CreateOrUpdate func (vr *AzureSqlVNetRuleManager) CreateOrUpdateSQLVNetRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string, VNetRG string, VNetName string, SubnetName string, IgnoreServiceEndpoint bool) (vnr sql.VirtualNetworkRule, err error) { - VNetRulesClient := azuresqlshared.GetGoVNetRulesClient() - SubnetClient := azuresqlshared.GetGoNetworkSubnetClient() + VNetRulesClient, err := azuresqlshared.GetGoVNetRulesClient() + if err != nil { + return sql.VirtualNetworkRule{}, err + } + + SubnetClient, err := azuresqlshared.GetGoNetworkSubnetClient() + if err != nil { + return sql.VirtualNetworkRule{}, err + } // Get ARM Resource ID of Subnet based on the VNET name, Subnet name and Subnet Address Prefix subnet, err := SubnetClient.Get(ctx, VNetRG, VNetName, SubnetName, "") diff --git a/pkg/resourcemanager/cosmosdbs/cosmosdb.go b/pkg/resourcemanager/cosmosdbs/cosmosdb.go index 8665da4084b..d55b6b756a7 100644 --- a/pkg/resourcemanager/cosmosdbs/cosmosdb.go +++ b/pkg/resourcemanager/cosmosdbs/cosmosdb.go @@ -40,103 +40,42 @@ func getCosmosDBClient() (documentdb.DatabaseAccountsClient, error) { // CreateOrUpdateCosmosDB creates a new CosmosDB func (*AzureCosmosDBManager) CreateOrUpdateCosmosDB( ctx context.Context, - groupName string, - cosmosDBName string, - location string, - kind v1alpha1.CosmosDBKind, - networkRule *[]v1alpha1.CosmosDBVirtualNetworkRule, - ipRules *[]string, - properties v1alpha1.CosmosDBProperties, - tags map[string]*string) (*documentdb.DatabaseAccount, error) { + accountName string, + spec v1alpha1.CosmosDBSpec, + tags map[string]*string) (*documentdb.DatabaseAccount, string, error) { cosmosDBClient, err := getCosmosDBClient() if err != nil { - return nil, err - } - - dbKind := documentdb.DatabaseAccountKind(kind) - sDBType := string(properties.DatabaseAccountOfferType) - bWriteLocal := bool(properties.EnableMultipleWriteLocations) - vnetEnabled := bool(properties.IsVirtualNetworkFilterEnabled) - - var capabilities []documentdb.Capability - if dbKind == documentdb.MongoDB && properties.MongoDBVersion == "3.6" { - capabilities = []documentdb.Capability{ - {Name: to.StringPtr("EnableMongo")}, - } - } else { - capabilities = make([]documentdb.Capability, 0) - } - - /* - * Current state of Locations and CosmosDB properties: - * Creating a Database account with CosmosDB requires - * that DatabaseAccountCreateUpdateProperties be sent over - * and currently we are not reading most of these values in - * as part of the Spec for CosmosDB. We are currently - * specifying a single Location as part of a location array - * which matches the location set for the overall CosmosDB - * instance. This matches the general behavior of creating - * a CosmosDB instance in the portal where the only - * geo-relicated region is the sole region the CosmosDB - * is created in. - */ - locationObj := documentdb.Location{ - ID: to.StringPtr(fmt.Sprintf("%s-%s", cosmosDBName, location)), - FailoverPriority: to.Int32Ptr(0), - LocationName: to.StringPtr(location), - } - locationsArray := []documentdb.Location{ - locationObj, - } - - vNetRulesSet := []documentdb.VirtualNetworkRule{} - if networkRule != nil { - for _, i := range *networkRule { - subnetID := i.SubnetID - ignoreEndpoint := i.IgnoreMissingVNetServiceEndpoint - vNetRulesSet = append(vNetRulesSet, documentdb.VirtualNetworkRule{ - ID: subnetID, - IgnoreMissingVNetServiceEndpoint: ignoreEndpoint, - }) - } - } - - sIPRules := "" - if ipRules != nil { - sIPRules = strings.Join(*ipRules, ",") + return nil, "", err } createUpdateParams := documentdb.DatabaseAccountCreateUpdateParameters{ - Location: to.StringPtr(location), + Location: &spec.Location, Tags: tags, - Name: &cosmosDBName, - Kind: dbKind, - Type: to.StringPtr("Microsoft.DocumentDb/databaseAccounts"), - ID: &cosmosDBName, + Name: &accountName, + Kind: documentdb.DatabaseAccountKind(spec.Kind), DatabaseAccountCreateUpdateProperties: &documentdb.DatabaseAccountCreateUpdateProperties{ - DatabaseAccountOfferType: &sDBType, - IsVirtualNetworkFilterEnabled: &vnetEnabled, - VirtualNetworkRules: &vNetRulesSet, - EnableMultipleWriteLocations: &bWriteLocal, - Locations: &locationsArray, - Capabilities: &capabilities, - IPRangeFilter: &sIPRules, + DatabaseAccountOfferType: getAccountOfferType(spec), + IsVirtualNetworkFilterEnabled: &spec.Properties.IsVirtualNetworkFilterEnabled, + VirtualNetworkRules: getVirtualNetworkRules(spec), + EnableMultipleWriteLocations: &spec.Properties.EnableMultipleWriteLocations, + Locations: getLocations(spec), + Capabilities: getCapabilities(spec), + IPRangeFilter: getIPRangeFilter(spec), }, } createUpdateFuture, err := cosmosDBClient.CreateOrUpdate( - ctx, groupName, cosmosDBName, createUpdateParams) - + ctx, spec.ResourceGroup, accountName, createUpdateParams) if err != nil { // initial create request failed, wrap error - return nil, err + return nil, "", err } result, err := createUpdateFuture.Result(cosmosDBClient) if err != nil { // there is no immediate result, wrap error - return &result, err + return &result, createUpdateFuture.PollingURL(), err } - return &result, nil + return &result, createUpdateFuture.PollingURL(), nil } // GetCosmosDB gets the cosmos db account @@ -219,3 +158,74 @@ func (*AzureCosmosDBManager) ListKeys( return &result, nil } + +func getAccountOfferType(spec v1alpha1.CosmosDBSpec) *string { + kind := string(spec.Properties.DatabaseAccountOfferType) + if kind == "" { + kind = string(documentdb.Standard) + } + return &kind +} + +func getLocations(spec v1alpha1.CosmosDBSpec) *[]documentdb.Location { + if spec.Locations == nil || len(*spec.Locations) <= 1 { + return &[]documentdb.Location{ + { + LocationName: to.StringPtr(spec.Location), + FailoverPriority: to.Int32Ptr(0), + IsZoneRedundant: to.BoolPtr(false), + }, + } + } + + locations := make([]documentdb.Location, len(*spec.Locations)) + for i, l := range *spec.Locations { + locations[i] = documentdb.Location{ + LocationName: to.StringPtr(l.LocationName), + FailoverPriority: to.Int32Ptr(l.FailoverPriority), + IsZoneRedundant: to.BoolPtr(l.IsZoneRedundant), + } + } + return &locations +} + +func getVirtualNetworkRules(spec v1alpha1.CosmosDBSpec) *[]documentdb.VirtualNetworkRule { + if spec.VirtualNetworkRules == nil { + return nil + } + + vNetRules := make([]documentdb.VirtualNetworkRule, len(*spec.VirtualNetworkRules)) + for i, r := range *spec.VirtualNetworkRules { + vNetRules[i] = documentdb.VirtualNetworkRule{ + ID: r.SubnetID, + IgnoreMissingVNetServiceEndpoint: r.IgnoreMissingVNetServiceEndpoint, + } + } + return &vNetRules +} + +func getCapabilities(spec v1alpha1.CosmosDBSpec) *[]documentdb.Capability { + capabilities := []documentdb.Capability{} + if spec.Kind == v1alpha1.CosmosDBKindMongoDB && spec.Properties.MongoDBVersion == "3.6" { + capabilities = []documentdb.Capability{ + {Name: to.StringPtr("EnableMongo")}, + } + } + if spec.Properties.Capabilities != nil { + for _, i := range *spec.Properties.Capabilities { + name := i.Name + capabilities = append(capabilities, documentdb.Capability{ + Name: name, + }) + } + } + return &capabilities +} + +func getIPRangeFilter(spec v1alpha1.CosmosDBSpec) *string { + sIPRules := "" + if spec.IPRules != nil { + sIPRules = strings.Join(*spec.IPRules, ",") + } + return &sIPRules +} diff --git a/pkg/resourcemanager/cosmosdbs/cosmosdb_manager.go b/pkg/resourcemanager/cosmosdbs/cosmosdb_manager.go index 23001b49bd0..abb75b5c1bc 100644 --- a/pkg/resourcemanager/cosmosdbs/cosmosdb_manager.go +++ b/pkg/resourcemanager/cosmosdbs/cosmosdb_manager.go @@ -21,7 +21,7 @@ func NewAzureCosmosDBManager(secretClient secrets.SecretClient) *AzureCosmosDBMa // CosmosDBManager client functions type CosmosDBManager interface { // CreateOrUpdateCosmosDB creates a new cosmos database account - CreateOrUpdateCosmosDB(ctx context.Context, groupName string, cosmosDBName string, location string, kind v1alpha1.CosmosDBKind, networkRule *[]v1alpha1.CosmosDBVirtualNetworkRule, ipRules *[]string, properties v1alpha1.CosmosDBProperties, tags map[string]*string) (*documentdb.DatabaseAccount, error) + CreateOrUpdateCosmosDB(ctx context.Context, cosmosDBName string, spec v1alpha1.CosmosDBSpec, tags map[string]*string) (*documentdb.DatabaseAccount, string, error) // GetCosmosDB gets a cosmos database account GetCosmosDB(ctx context.Context, groupName string, cosmosDBName string) (*documentdb.DatabaseAccount, error) diff --git a/pkg/resourcemanager/cosmosdbs/cosmosdb_reconcile.go b/pkg/resourcemanager/cosmosdbs/cosmosdb_reconcile.go index b06554f1fd1..b0ec43081b3 100644 --- a/pkg/resourcemanager/cosmosdbs/cosmosdb_reconcile.go +++ b/pkg/resourcemanager/cosmosdbs/cosmosdb_reconcile.go @@ -8,10 +8,12 @@ import ( "fmt" "strings" + "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2015-04-08/documentdb" "github.com/Azure/azure-service-operator/api/v1alpha1" "github.com/Azure/azure-service-operator/pkg/errhelp" "github.com/Azure/azure-service-operator/pkg/helpers" "github.com/Azure/azure-service-operator/pkg/resourcemanager" + "github.com/Azure/azure-service-operator/pkg/resourcemanager/pollclient" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -41,6 +43,28 @@ func (m *AzureCosmosDBManager) Ensure(ctx context.Context, obj runtime.Object, o } instance.Status.Provisioned = false + if instance.Status.PollingURL != "" { + pollClient := pollclient.NewPollClient() + pollResponse, err := pollClient.Get(ctx, instance.Status.PollingURL) + if err != nil { + instance.Status.Provisioning = false + return false, err + } + + // response is not ready yet + if pollResponse.Status == "Dequeued" { + return false, nil + } + + instance.Status.PollingURL = "" + + if pollResponse.Status == "Failed" { + instance.Status.Provisioning = false + instance.Status.Message = pollResponse.Error.Error() + return true, nil + } + } + // get the instance and update status db, err := m.GetCosmosDB(ctx, instance.Spec.ResourceGroup, instance.Name) if err != nil { @@ -67,7 +91,7 @@ func (m *AzureCosmosDBManager) Ensure(ctx context.Context, obj runtime.Object, o if instance.Status.State == "Succeeded" { // provisioning is complete, update the secrets - if err = m.createOrUpdateAccountKeysSecret(ctx, instance); err != nil { + if err = m.createOrUpdateSecret(ctx, instance, db); err != nil { instance.Status.Message = err.Error() return false, err } @@ -91,20 +115,7 @@ func (m *AzureCosmosDBManager) Ensure(ctx context.Context, obj runtime.Object, o tags := helpers.LabelsToTags(instance.GetLabels()) accountName := instance.ObjectMeta.Name - groupName := instance.Spec.ResourceGroup - location := instance.Spec.Location - kind := instance.Spec.Kind - networkRule := instance.Spec.VirtualNetworkRules - ipRules := instance.Spec.IPRules - - cosmosDBProperties := v1alpha1.CosmosDBProperties{ - DatabaseAccountOfferType: instance.Spec.Properties.DatabaseAccountOfferType, - EnableMultipleWriteLocations: instance.Spec.Properties.EnableMultipleWriteLocations, - MongoDBVersion: instance.Spec.Properties.MongoDBVersion, - IsVirtualNetworkFilterEnabled: instance.Spec.Properties.IsVirtualNetworkFilterEnabled, - } - - db, err = m.CreateOrUpdateCosmosDB(ctx, groupName, accountName, location, kind, networkRule, ipRules, cosmosDBProperties, tags) + db, pollingUrl, err := m.CreateOrUpdateCosmosDB(ctx, accountName, instance.Spec, tags) if err != nil { azerr := errhelp.NewAzureErrorAzureError(err) instance.Status.Message = err.Error() @@ -114,8 +125,9 @@ func (m *AzureCosmosDBManager) Ensure(ctx context.Context, obj runtime.Object, o instance.Status.State = "Creating" instance.Status.Message = "Resource request successfully submitted to Azure" instance.Status.SpecHash = hash + instance.Status.PollingURL = pollingUrl return false, nil - case errhelp.InvalidResourceLocation, errhelp.LocationNotAvailableForResourceType: + case errhelp.InvalidResourceLocation, errhelp.LocationNotAvailableForResourceType, errhelp.BadRequest: instance.Status.Provisioning = false instance.Status.Message = azerr.Error() return true, nil @@ -136,7 +148,7 @@ func (m *AzureCosmosDBManager) Ensure(ctx context.Context, obj runtime.Object, o return false, err } - if err = m.createOrUpdateAccountKeysSecret(ctx, instance); err != nil { + if err = m.createOrUpdateSecret(ctx, instance, db); err != nil { instance.Status.Message = err.Error() return false, err } @@ -166,12 +178,6 @@ func (m *AzureCosmosDBManager) Delete(ctx context.Context, obj runtime.Object, o return false, err } - // if the resource is in a failed state it was never created or could never be verified - // so we skip attempting to delete the resrouce from Azure - if instance.Status.FailedProvisioning { - return false, nil - } - groupName := instance.Spec.ResourceGroup accountName := instance.ObjectMeta.Name @@ -193,7 +199,8 @@ func (m *AzureCosmosDBManager) Delete(ctx context.Context, obj runtime.Object, o errhelp.ResourceGroupNotFoundErrorCode, } if helpers.ContainsString(notFound, azerr.Type) { - return false, m.deleteAccountKeysSecret(ctx, instance) + _ = m.deleteSecret(ctx, instance) + return false, nil } // unhandled error @@ -201,7 +208,8 @@ func (m *AzureCosmosDBManager) Delete(ctx context.Context, obj runtime.Object, o return false, err } - return false, m.deleteAccountKeysSecret(ctx, instance) + _ = m.deleteSecret(ctx, instance) + return false, nil } // GetParents returns the parents of cosmosdb @@ -239,7 +247,7 @@ func (m *AzureCosmosDBManager) convert(obj runtime.Object) (*v1alpha1.CosmosDB, return db, nil } -func (m *AzureCosmosDBManager) createOrUpdateAccountKeysSecret(ctx context.Context, instance *v1alpha1.CosmosDB) error { +func (m *AzureCosmosDBManager) createOrUpdateSecret(ctx context.Context, instance *v1alpha1.CosmosDB, db *documentdb.DatabaseAccount) error { result, err := m.ListKeys(ctx, instance.Spec.ResourceGroup, instance.ObjectMeta.Name) if err != nil { return err @@ -250,21 +258,24 @@ func (m *AzureCosmosDBManager) createOrUpdateAccountKeysSecret(ctx context.Conte Namespace: instance.Namespace, } secretData := map[string][]byte{ + "primaryEndpoint": []byte(*db.DocumentEndpoint), "primaryConnectionString": []byte(*result.PrimaryMasterKey), "secondaryConnectionString": []byte(*result.SecondaryMasterKey), "primaryReadonlyMasterKey": []byte(*result.PrimaryReadonlyMasterKey), "secondaryReadonlyMasterKey": []byte(*result.SecondaryReadonlyMasterKey), } - err = m.SecretClient.Upsert(ctx, secretKey, secretData) - if err != nil { - return err + if db.DatabaseAccountProperties.ReadLocations != nil { + for _, l := range *db.DatabaseAccountProperties.ReadLocations { + safeLocationName := helpers.RemoveNonAlphaNumeric(strings.ToLower(*l.LocationName)) + secretData[safeLocationName+"Endpoint"] = []byte(*l.DocumentEndpoint) + } } - return nil + return m.SecretClient.Upsert(ctx, secretKey, secretData) } -func (m *AzureCosmosDBManager) deleteAccountKeysSecret(ctx context.Context, instance *v1alpha1.CosmosDB) error { +func (m *AzureCosmosDBManager) deleteSecret(ctx context.Context, instance *v1alpha1.CosmosDB) error { secretKey := types.NamespacedName{ Name: instance.Name, Namespace: instance.Namespace, diff --git a/pkg/resourcemanager/eventhubs/consumergroup.go b/pkg/resourcemanager/eventhubs/consumergroup.go index 4e999f58290..6a6caf556b7 100644 --- a/pkg/resourcemanager/eventhubs/consumergroup.go +++ b/pkg/resourcemanager/eventhubs/consumergroup.go @@ -6,6 +6,7 @@ package eventhubs import ( "context" "fmt" + "net/http" "strings" "github.com/Azure/azure-service-operator/api/v1alpha1" @@ -28,12 +29,15 @@ func NewConsumerGroupClient() *azureConsumerGroupManager { return &azureConsumerGroupManager{} } -func getConsumerGroupsClient() eventhub.ConsumerGroupsClient { +func getConsumerGroupsClient() (eventhub.ConsumerGroupsClient, error) { consumerGroupClient := eventhub.NewConsumerGroupsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer() + auth, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return eventhub.ConsumerGroupsClient{}, err + } consumerGroupClient.Authorizer = auth consumerGroupClient.AddToUserAgent(config.UserAgent()) - return consumerGroupClient + return consumerGroupClient, nil } // CreateConsumerGroup creates an Event Hub Consumer Group @@ -44,7 +48,10 @@ func getConsumerGroupsClient() eventhub.ConsumerGroupsClient { // consumerGroupName - the consumer group name // parameters - parameters supplied to create or update a consumer group resource. func (_ *azureConsumerGroupManager) CreateConsumerGroup(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, consumerGroupName string) (eventhub.ConsumerGroup, error) { - consumerGroupClient := getConsumerGroupsClient() + consumerGroupClient, err := getConsumerGroupsClient() + if err != nil { + return eventhub.ConsumerGroup{}, err + } parameters := eventhub.ConsumerGroup{} return consumerGroupClient.CreateOrUpdate( @@ -65,7 +72,15 @@ func (_ *azureConsumerGroupManager) CreateConsumerGroup(ctx context.Context, res // eventHubName - the Event Hub name // consumerGroupName - the consumer group name func (_ *azureConsumerGroupManager) DeleteConsumerGroup(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, consumerGroupName string) (result autorest.Response, err error) { - consumerGroupClient := getConsumerGroupsClient() + consumerGroupClient, err := getConsumerGroupsClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + return consumerGroupClient.Delete( ctx, resourceGroupName, @@ -73,12 +88,15 @@ func (_ *azureConsumerGroupManager) DeleteConsumerGroup(ctx context.Context, res eventHubName, consumerGroupName, ) - } //GetConsumerGroup gets consumer group description for the specified Consumer Group. func (_ *azureConsumerGroupManager) GetConsumerGroup(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, consumerGroupName string) (eventhub.ConsumerGroup, error) { - consumerGroupClient := getConsumerGroupsClient() + consumerGroupClient, err := getConsumerGroupsClient() + if err != nil { + return eventhub.ConsumerGroup{}, err + } + return consumerGroupClient.Get(ctx, resourceGroupName, namespaceName, eventHubName, consumerGroupName) } diff --git a/pkg/resourcemanager/eventhubs/hub.go b/pkg/resourcemanager/eventhubs/hub.go index a216702a724..ba6fcce7e96 100644 --- a/pkg/resourcemanager/eventhubs/hub.go +++ b/pkg/resourcemanager/eventhubs/hub.go @@ -31,12 +31,15 @@ type azureEventHubManager struct { Scheme *runtime.Scheme } -func getHubsClient() eventhub.EventHubsClient { +func getHubsClient() (eventhub.EventHubsClient, error) { hubClient := eventhub.NewEventHubsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer() + auth, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return eventhub.EventHubsClient{}, err + } hubClient.Authorizer = auth hubClient.AddToUserAgent(config.UserAgent()) - return hubClient + return hubClient, nil } func NewEventhubClient(secretClient secrets.SecretClient, scheme *runtime.Scheme) *azureEventHubManager { @@ -47,7 +50,15 @@ func NewEventhubClient(secretClient secrets.SecretClient, scheme *runtime.Scheme } func (_ *azureEventHubManager) DeleteHub(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string) (result autorest.Response, err error) { - hubClient := getHubsClient() + hubClient, err := getHubsClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + return hubClient.Delete(ctx, resourceGroupName, namespaceName, @@ -56,7 +67,10 @@ func (_ *azureEventHubManager) DeleteHub(ctx context.Context, resourceGroupName } func (_ *azureEventHubManager) CreateHub(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, MessageRetentionInDays int32, PartitionCount int32, captureDescription *eventhub.CaptureDescription) (eventhub.Model, error) { - hubClient := getHubsClient() + hubClient, err := getHubsClient() + if err != nil { + return eventhub.Model{}, err + } // MessageRetentionInDays - Number of days to retain the events for this Event Hub, value should be 1 to 7 days if MessageRetentionInDays < 1 || MessageRetentionInDays > 7 { @@ -86,17 +100,29 @@ func (_ *azureEventHubManager) CreateHub(ctx context.Context, resourceGroupName } func (_ *azureEventHubManager) GetHub(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string) (eventhub.Model, error) { - hubClient := getHubsClient() + hubClient, err := getHubsClient() + if err != nil { + return eventhub.Model{}, err + } + return hubClient.Get(ctx, resourceGroupName, namespaceName, eventHubName) } func (_ *azureEventHubManager) CreateOrUpdateAuthorizationRule(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, authorizationRuleName string, parameters eventhub.AuthorizationRule) (result eventhub.AuthorizationRule, err error) { - hubClient := getHubsClient() + hubClient, err := getHubsClient() + if err != nil { + return eventhub.AuthorizationRule{}, err + } + return hubClient.CreateOrUpdateAuthorizationRule(ctx, resourceGroupName, namespaceName, eventHubName, authorizationRuleName, parameters) } func (_ *azureEventHubManager) ListKeys(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, authorizationRuleName string) (result eventhub.AccessKeys, err error) { - hubClient := getHubsClient() + hubClient, err := getHubsClient() + if err != nil { + return eventhub.AccessKeys{}, err + } + return hubClient.ListKeys(ctx, resourceGroupName, namespaceName, eventHubName, authorizationRuleName) } diff --git a/pkg/resourcemanager/eventhubs/namespace.go b/pkg/resourcemanager/eventhubs/namespace.go index 262d5892a3c..23cb5d7c3e6 100644 --- a/pkg/resourcemanager/eventhubs/namespace.go +++ b/pkg/resourcemanager/eventhubs/namespace.go @@ -29,12 +29,15 @@ import ( type azureEventHubNamespaceManager struct { } -func getNamespacesClient() eventhub.NamespacesClient { +func getNamespacesClient() (eventhub.NamespacesClient, error) { nsClient := eventhub.NewNamespacesClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer() + auth, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return eventhub.NamespacesClient{}, err + } nsClient.Authorizer = auth nsClient.AddToUserAgent(config.UserAgent()) - return nsClient + return nsClient, nil } func NewEventHubNamespaceClient() *azureEventHubNamespaceManager { @@ -47,7 +50,15 @@ func NewEventHubNamespaceClient() *azureEventHubNamespaceManager { // namespaceName - the Namespace name func (_ *azureEventHubNamespaceManager) DeleteNamespace(ctx context.Context, resourceGroupName string, namespaceName string) (autorest.Response, error) { - nsClient := getNamespacesClient() + nsClient, err := getNamespacesClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + future, err := nsClient.Delete(ctx, resourceGroupName, namespaceName) @@ -60,7 +71,11 @@ func (_ *azureEventHubNamespaceManager) DeleteNamespace(ctx context.Context, res // resourceGroupName - name of the resource group within the azure subscription. // namespaceName - the Namespace name func (_ *azureEventHubNamespaceManager) GetNamespace(ctx context.Context, resourceGroupName string, namespaceName string) (*eventhub.EHNamespace, error) { - nsClient := getNamespacesClient() + nsClient, err := getNamespacesClient() + if err != nil { + return nil, err + } + x, err := nsClient.Get(ctx, resourceGroupName, namespaceName) if err != nil { @@ -78,7 +93,11 @@ func (_ *azureEventHubNamespaceManager) GetNamespace(ctx context.Context, resour // namespaceName - the Namespace name // location - azure region func (_ *azureEventHubNamespaceManager) CreateNamespaceAndWait(ctx context.Context, resourceGroupName string, namespaceName string, location string) (*eventhub.EHNamespace, error) { - nsClient := getNamespacesClient() + nsClient, err := getNamespacesClient() + if err != nil { + return nil, err + } + future, err := nsClient.CreateOrUpdate( ctx, resourceGroupName, @@ -101,7 +120,10 @@ func (_ *azureEventHubNamespaceManager) CreateNamespaceAndWait(ctx context.Conte } func (_ *azureEventHubNamespaceManager) CreateNamespace(ctx context.Context, resourceGroupName string, namespaceName string, location string, sku v1alpha1.EventhubNamespaceSku, properties v1alpha1.EventhubNamespaceProperties) (eventhub.EHNamespace, error) { - nsClient := getNamespacesClient() + nsClient, err := getNamespacesClient() + if err != nil { + return eventhub.EHNamespace{}, err + } // Construct the Sku struct for the namespace namespaceSku := eventhub.Sku{ @@ -156,17 +178,28 @@ func (_ *azureEventHubNamespaceManager) CreateNamespace(ctx context.Context, res } func (nr *azureEventHubNamespaceManager) CreateNetworkRuleSet(ctx context.Context, groupname string, namespace string, rules eventhub.NetworkRuleSet) (result eventhub.NetworkRuleSet, err error) { - namespaceclient := getNamespacesClient() + namespaceclient, err := getNamespacesClient() + if err != nil { + return eventhub.NetworkRuleSet{}, err + } + return namespaceclient.CreateOrUpdateNetworkRuleSet(ctx, groupname, namespace, rules) } func (nr *azureEventHubNamespaceManager) GetNetworkRuleSet(ctx context.Context, groupName string, namespace string) (ruleset eventhub.NetworkRuleSet, err error) { - namespaceclient := getNamespacesClient() + namespaceclient, err := getNamespacesClient() + if err != nil { + return eventhub.NetworkRuleSet{}, err + } + return namespaceclient.GetNetworkRuleSet(ctx, groupName, namespace) } func (nr *azureEventHubNamespaceManager) DeleteNetworkRuleSet(ctx context.Context, groupName string, namespace string) (result eventhub.NetworkRuleSet, err error) { - namespaceclient := getNamespacesClient() + namespaceclient, err := getNamespacesClient() + if err != nil { + return eventhub.NetworkRuleSet{}, err + } // SDK does not have a DeleteNetworkRuleSet function, so setting rules to empty // and calling Create to delete the rules diff --git a/pkg/resourcemanager/mock/appinsights/appinsights.go b/pkg/resourcemanager/mock/appinsights/appinsights.go deleted file mode 100644 index 6d1ce44cb02..00000000000 --- a/pkg/resourcemanager/mock/appinsights/appinsights.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package appinsights - -import ( - "context" - "errors" - "fmt" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/appinsights/mgmt/2015-05-01/insights" - "github.com/Azure/azure-service-operator/api/v1alpha1" - resourcemanager "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" -) - -// MockAppInsightsManager mocks the implementation of an AppInsights Manager type -type MockAppInsightsManager struct { - Scheme *runtime.Scheme - resourceGroupName string - appinsights []insights.ApplicationInsightsComponent -} - -// NewMockAppInsightsManager creates a new MockAppInsightsManager -func NewMockAppInsightsManager(scheme *runtime.Scheme) *MockAppInsightsManager { - return &MockAppInsightsManager{ - Scheme: scheme, - appinsights: []insights.ApplicationInsightsComponent{}, - } -} - -// GetParents fetches the ARM hierarchy of resources for this operator -func (m *MockAppInsightsManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} - -// CreateAppInsights creates or updates a mock Application Insights service -func (m *MockAppInsightsManager) CreateAppInsights( - ctx context.Context, - resourceGroupName string, - kind string, - applicationType string, - location string, - resourceName string) (insights.ApplicationInsightsComponent, error) { - - index, _ := findAppInsight(m.appinsights, func(i insights.ApplicationInsightsComponent) bool { - return *i.Name == resourceName - }) - - insights := insights.ApplicationInsightsComponent{ - Kind: to.StringPtr(kind), - Location: to.StringPtr(location), - Name: to.StringPtr(resourceName), - } - - if index == -1 { - m.appinsights = append(m.appinsights, insights) - } - - return insights, nil -} - -// Delete removes the operator from desired state -func (m *MockAppInsightsManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := m.convert(obj) - if err != nil { - return false, err - } - - _, err = m.DeleteAppInsights(ctx, instance.Spec.ResourceGroup, instance.ObjectMeta.Name) - if err != nil { - return false, err - } - - return false, nil -} - -// DeleteAppInsights removes an Application Insights service from a subscription -func (m *MockAppInsightsManager) DeleteAppInsights(ctx context.Context, resourceGroupName string, resourceName string) (autorest.Response, error) { - appinsights := m.appinsights - - index, _ := findAppInsight(appinsights, func(i insights.ApplicationInsightsComponent) bool { - return *i.Name == resourceName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("appinsights instance not found") - } - - m.appinsights = append(appinsights[:index], appinsights[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -// GetAppInsights fetches an Application Insights service reference -func (m *MockAppInsightsManager) GetAppInsights(ctx context.Context, resourceGroupName string, resourceName string) (insights.ApplicationInsightsComponent, error) { - appinsights := m.appinsights - - index, appinsight := findAppInsight(appinsights, func(i insights.ApplicationInsightsComponent) bool { - return *i.Name == resourceName - }) - - if index == -1 { - return insights.ApplicationInsightsComponent{ - Response: helpers.GetRestResponse(http.StatusNotFound), - }, errors.New("appinsights instance not found") - } - - appinsight.Response = helpers.GetRestResponse(http.StatusOK) - return appinsight, nil -} - -// Ensure checks the desired state of the operator -func (m *MockAppInsightsManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - i, err := m.convert(obj) - if err != nil { - return true, err - } - - _, _ = m.CreateAppInsights(ctx, i.Spec.ResourceGroup, "web", "other", i.Spec.Location, i.Name) - - i.Status.Provisioned = true - - return true, nil -} - -func findAppInsight(res []insights.ApplicationInsightsComponent, predicate func(insights.ApplicationInsightsComponent) bool) (int, insights.ApplicationInsightsComponent) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, insights.ApplicationInsightsComponent{} -} - -func (m *MockAppInsightsManager) convert(obj runtime.Object) (*v1alpha1.AppInsights, error) { - i, ok := obj.(*v1alpha1.AppInsights) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return i, nil -} diff --git a/pkg/resourcemanager/mock/azuresql/azuresqldb.go b/pkg/resourcemanager/mock/azuresql/azuresqldb.go deleted file mode 100644 index 9e9403b2a5e..00000000000 --- a/pkg/resourcemanager/mock/azuresql/azuresqldb.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package azuresql - -import ( - "context" - "errors" - "fmt" - "net/http" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - azuresqlshared "github.com/Azure/azure-service-operator/pkg/resourcemanager/azuresql/azuresqlshared" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" -) - -type MockSqlDbManager struct { - resourceGroupName string - sqlDbs []MockSqlDbResource -} - -type MockSqlDbResource struct { - resourceGroupName string - sqlServerName string - sqlDb sql.Database -} - -func NewMockSqlDbManager() *MockSqlDbManager { - return &MockSqlDbManager{} -} - -func findSqlDb(res []MockSqlDbResource, predicate func(MockSqlDbResource) bool) (int, MockSqlDbResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, MockSqlDbResource{} -} - -//CreateorUpdateDB creates a sql Db -func (manager *MockSqlDbManager) CreateOrUpdateDB(ctx context.Context, resourceGroupName string, location string, serverName string, tags map[string]*string, properties azuresqlshared.SQLDatabaseProperties) (sql.DatabasesCreateOrUpdateFuture, error) { - index, _ := findSqlDb(manager.sqlDbs, func(s MockSqlDbResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlDb.Name == properties.DatabaseName - }) - - sqlD := sql.Database{ - Location: to.StringPtr(location), - Name: to.StringPtr(properties.DatabaseName), - } - - q := MockSqlDbResource{ - resourceGroupName: resourceGroupName, - sqlServerName: serverName, - sqlDb: sqlD, - } - - if index == -1 { - manager.sqlDbs = append(manager.sqlDbs, q) - } - - return sql.DatabasesCreateOrUpdateFuture{}, nil - -} - -func (manager *MockSqlDbManager) GetDB(ctx context.Context, resourceGroupName string, serverName string, databaseName string) (result sql.Database, err error) { - index, _ := findSqlDb(manager.sqlDbs, func(s MockSqlDbResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlDb.Name == databaseName - }) - - if index == -1 { - return sql.Database{}, errors.New("Sql Db Not Found") - } - - return manager.sqlDbs[index].sqlDb, nil -} - -//GetServer gets a sql server -func (manager *MockSqlDbManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - sqlManager := MockSqlServerManager{} - return sqlManager.GetServer(ctx, resourceGroupName, serverName) -} - -// DeleteDb removes the sql db -func (manager *MockSqlDbManager) DeleteDB(ctx context.Context, resourceGroupName string, serverName string, databaseName string) (result autorest.Response, err error) { - sqlDbs := manager.sqlDbs - - index, _ := findSqlDb(manager.sqlDbs, func(s MockSqlDbResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlDb.Name == databaseName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("Sql Db Not Found") - } - - manager.sqlDbs = append(sqlDbs[:index], sqlDbs[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -func (db *MockSqlDbManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := db.convert(obj) - if err != nil { - return false, err - } - - location := instance.Spec.Location - groupName := instance.Spec.ResourceGroup - server := instance.Spec.Server - dbName := instance.ObjectMeta.Name - dbEdition := instance.Spec.Edition - tags := map[string]*string{} - - azureSqlDatabaseProperties := azuresqlshared.SQLDatabaseProperties{ - DatabaseName: dbName, - Edition: dbEdition, - } - - _, err = db.CreateOrUpdateDB(ctx, groupName, location, server, tags, azureSqlDatabaseProperties) - if err != nil { - return false, err - } - - instance.Status.Provisioning = true - instance.Status.Provisioned = true - - return true, nil -} - -func (db *MockSqlDbManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := db.convert(obj) - if err != nil { - return false, err - } - - groupName := instance.Spec.ResourceGroup - server := instance.Spec.Server - dbName := instance.ObjectMeta.Name - - _, err = db.DeleteDB(ctx, groupName, server, dbName) - if err != nil { - return false, err - } - - return false, nil -} - -func (g *MockSqlDbManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return nil, nil -} - -func (*MockSqlDbManager) convert(obj runtime.Object) (*azurev1alpha1.AzureSqlDatabase, error) { - local, ok := obj.(*azurev1alpha1.AzureSqlDatabase) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/azuresql/azuresqlfailovergroup.go b/pkg/resourcemanager/mock/azuresql/azuresqlfailovergroup.go deleted file mode 100644 index a59f02837b2..00000000000 --- a/pkg/resourcemanager/mock/azuresql/azuresqlfailovergroup.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package azuresql - -import ( - "context" - "errors" - "fmt" - "net/http" - - "k8s.io/apimachinery/pkg/runtime" - - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - azuresqlshared "github.com/Azure/azure-service-operator/pkg/resourcemanager/azuresql/azuresqlshared" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" -) - -type MockSqlFailoverGroupManager struct { - sqlFailoverGroups []MockSqlFailoverResource -} - -type MockSqlFailoverResource struct { - resourceGroupName string - sqlServerName string - sqlFailover sql.FailoverGroup -} - -func NewMockSqlFailoverGroupManager() *MockSqlFailoverGroupManager { - return &MockSqlFailoverGroupManager{} -} - -func findSqlFailoverGroup(res []MockSqlFailoverResource, predicate func(MockSqlFailoverResource) bool) (int, MockSqlFailoverResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, MockSqlFailoverResource{} -} - -func (manager *MockSqlFailoverGroupManager) CreateOrUpdateFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failovergroupname string, properties azuresqlshared.SQLFailoverGroupProperties) (result sql.FailoverGroupsCreateOrUpdateFuture, err error) { - index, _ := findSqlFailoverGroup(manager.sqlFailoverGroups, func(s MockSqlFailoverResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlFailover.Name == failovergroupname - }) - - sqlFG := sql.FailoverGroup{ - Name: to.StringPtr(failovergroupname), - } - - q := MockSqlFailoverResource{ - resourceGroupName: resourceGroupName, - sqlServerName: serverName, - sqlFailover: sqlFG, - } - - if index == -1 { - manager.sqlFailoverGroups = append(manager.sqlFailoverGroups, q) - } - - return sql.FailoverGroupsCreateOrUpdateFuture{}, nil -} - -//DeleteFailoverGroup deletes a failover group -func (manager *MockSqlFailoverGroupManager) DeleteFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failoverGroupName string) (result autorest.Response, err error) { - sqlFailoverGroups := manager.sqlFailoverGroups - - index, _ := findSqlFailoverGroup(manager.sqlFailoverGroups, func(s MockSqlFailoverResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlFailover.Name == failoverGroupName - }) - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("Sql Firewall Rule Found") - } - - manager.sqlFailoverGroups = append(sqlFailoverGroups[:index], sqlFailoverGroups[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -//GetFailoverGroup gets a failover group -func (manager *MockSqlFailoverGroupManager) GetFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failovergroupname string) (result sql.FailoverGroup, err error) { - - index, _ := findSqlFailoverGroup(manager.sqlFailoverGroups, func(s MockSqlFailoverResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlFailover.Name == failovergroupname - }) - if index == -1 { - return sql.FailoverGroup{}, errors.New("Sql FailoverGroup Not Found") - } - - return manager.sqlFailoverGroups[index].sqlFailover, nil -} - -//GetServer gets a sql server -func (manager *MockSqlFailoverGroupManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - sqlManager := MockSqlServerManager{} - return sqlManager.GetServer(ctx, resourceGroupName, serverName) -} - -//GetDb gets a sql db server -func (manager *MockSqlFailoverGroupManager) GetDB(ctx context.Context, resourceGroupName string, serverName string, databaseName string) (result sql.Database, err error) { - sqlManager := MockSqlDbManager{} - return sqlManager.GetDB(ctx, resourceGroupName, serverName, databaseName) -} - -func (fg *MockSqlFailoverGroupManager) Ensure(ctx context.Context, obj runtime.Object) (bool, error) { - return true, nil -} - -func (fg *MockSqlFailoverGroupManager) Delete(ctx context.Context, obj runtime.Object) (bool, error) { - return true, nil -} - -func (g *MockSqlFailoverGroupManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} - -func (*MockSqlFailoverGroupManager) convert(obj runtime.Object) (*azurev1alpha1.AzureSqlFailoverGroup, error) { - local, ok := obj.(*azurev1alpha1.AzureSqlFailoverGroup) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/azuresql/azuresqlfirewallrule.go b/pkg/resourcemanager/mock/azuresql/azuresqlfirewallrule.go deleted file mode 100644 index ab6c35b62a0..00000000000 --- a/pkg/resourcemanager/mock/azuresql/azuresqlfirewallrule.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package azuresql - -import ( - "context" - "errors" - "fmt" - - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" -) - -type MockSqlFirewallRuleManager struct { - sqlFirewallRules []MockSqlFirewallRuleResource -} - -type MockSqlFirewallRuleResource struct { - resourceGroupName string - sqlServerName string - sqlFirewallRule sql.FirewallRule -} - -func NewMockSqlFirewallRuleManager() *MockSqlFirewallRuleManager { - return &MockSqlFirewallRuleManager{} -} - -func findSqlFirewallRule(res []MockSqlFirewallRuleResource, predicate func(MockSqlFirewallRuleResource) bool) (int, MockSqlFirewallRuleResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, MockSqlFirewallRuleResource{} -} - -// CreateOrUpdateSQLFirewallRule creates a sql firewall rule -func (manager *MockSqlFirewallRuleManager) CreateOrUpdateSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string, startIP string, endIP string) (result bool, err error) { - index, _ := findSqlFirewallRule(manager.sqlFirewallRules, func(s MockSqlFirewallRuleResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlFirewallRule.Name == ruleName - }) - - sqlFR := sql.FirewallRule{ - Name: to.StringPtr(ruleName), - } - - q := MockSqlFirewallRuleResource{ - resourceGroupName: resourceGroupName, - sqlServerName: serverName, - sqlFirewallRule: sqlFR, - } - - if index == -1 { - manager.sqlFirewallRules = append(manager.sqlFirewallRules, q) - } - - return true, nil -} - -// GetSQLFirewallRule gets a sql firewall rule -func (manager *MockSqlFirewallRuleManager) GetSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (result sql.FirewallRule, err error) { - index, _ := findSqlFirewallRule(manager.sqlFirewallRules, func(s MockSqlFirewallRuleResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlFirewallRule.Name == ruleName - }) - - if index == -1 { - return sql.FirewallRule{}, errors.New("Sql Firewall Rule Not Found") - } - - return manager.sqlFirewallRules[index].sqlFirewallRule, nil -} - -//GetServer gets a sql server -func (manager *MockSqlFirewallRuleManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - sqlManager := MockSqlServerManager{} - return sqlManager.GetServer(ctx, resourceGroupName, serverName) -} - -// DeleteSQLFirewallRule deletes a sql firewall rule -func (manager *MockSqlFirewallRuleManager) DeleteSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (err error) { - - sqlFirewallRules := manager.sqlFirewallRules - - index, _ := findSqlFirewallRule(manager.sqlFirewallRules, func(s MockSqlFirewallRuleResource) bool { - return s.resourceGroupName == resourceGroupName && s.sqlServerName == serverName && *s.sqlFirewallRule.Name == ruleName - }) - - if index == -1 { - return errors.New("Sql Firewall Rule Found") - } - - manager.sqlFirewallRules = append(sqlFirewallRules[:index], sqlFirewallRules[index+1:]...) - - return nil -} - -func (fw *MockSqlFirewallRuleManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - return true, nil -} - -func (fw *MockSqlFirewallRuleManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - return true, nil -} - -func (g *MockSqlFirewallRuleManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} - -func (*MockSqlFirewallRuleManager) convert(obj runtime.Object) (*azurev1alpha1.AzureSqlFirewallRule, error) { - local, ok := obj.(*azurev1alpha1.AzureSqlFirewallRule) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/azuresql/azuresqlserver.go b/pkg/resourcemanager/mock/azuresql/azuresqlserver.go deleted file mode 100644 index 436b75b3de3..00000000000 --- a/pkg/resourcemanager/mock/azuresql/azuresqlserver.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package azuresql - -import ( - "context" - "errors" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" - azuresqlshared "github.com/Azure/azure-service-operator/pkg/resourcemanager/azuresql/azuresqlshared" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest/to" - - "github.com/Azure/go-autorest/autorest" -) - -type MockSqlServerManager struct { - resourceGroupName string - sqlServers []MockSqlServerResource -} - -type MockSqlServerResource struct { - resourceGroupName string - sqlServer sql.Server -} - -func NewMockSqlServerManager() *MockSqlServerManager { - return &MockSqlServerManager{} -} - -func findSqlServer(res []MockSqlServerResource, predicate func(MockSqlServerResource) bool) (int, error) { - for index, r := range res { - if predicate(r) { - return index, nil - } - } - return -1, errors.New("not found") -} - -// CreateOrUpdateSqlServer creates a new sql server -func (manager *MockSqlServerManager) CreateOrUpdateSQLServer(ctx context.Context, resourceGroupName string, location string, serverName string, tags map[string]*string, properties azuresqlshared.SQLServerProperties, forceUpdate bool) (result sql.Server, err error) { - index, _ := findSqlServer(manager.sqlServers, func(s MockSqlServerResource) bool { - return s.resourceGroupName == resourceGroupName && *s.sqlServer.Name == serverName - }) - - sqlS := sql.Server{ - Response: helpers.GetRestResponse(http.StatusCreated), - Location: to.StringPtr(location), - Name: to.StringPtr(serverName), - } - - q := MockSqlServerResource{ - resourceGroupName: resourceGroupName, - sqlServer: sqlS, - } - - if index == -1 { - manager.sqlServers = append(manager.sqlServers, q) - } - - return q.sqlServer, nil -} - -// DeleteSQLServer removes the sqlserver -func (manager *MockSqlServerManager) DeleteSQLServer(ctx context.Context, resourceGroupName string, serverName string) (result autorest.Response, err error) { - sqlServers := manager.sqlServers - - index, _ := findSqlServer(sqlServers, func(s MockSqlServerResource) bool { - return s.resourceGroupName == resourceGroupName && *s.sqlServer.Name == serverName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("Sql Server Not Found") - } - - manager.sqlServers = append(sqlServers[:index], sqlServers[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -// GetServer gets a sql server -func (manager *MockSqlServerManager) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - index, _ := findSqlServer(manager.sqlServers, func(s MockSqlServerResource) bool { - return s.resourceGroupName == resourceGroupName && *s.sqlServer.Name == serverName - }) - - if index == -1 { - return sql.Server{}, errors.New("Sql Server Not Found") - } - - state := "Ready" - serverProperties := sql.ServerProperties{State: &state} - server := manager.sqlServers[index].sqlServer - server.ServerProperties = &serverProperties - - return server, nil -} diff --git a/pkg/resourcemanager/mock/azuresql/azuresqluser.go b/pkg/resourcemanager/mock/azuresql/azuresqluser.go deleted file mode 100644 index 84487197986..00000000000 --- a/pkg/resourcemanager/mock/azuresql/azuresqluser.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package azuresql - -import ( - "context" - "errors" - "fmt" - - "database/sql" - dbsql "database/sql" - - "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - azuresqluser "github.com/Azure/azure-service-operator/pkg/resourcemanager/azuresql/azuresqluser" - "k8s.io/apimachinery/pkg/runtime" -) - -type MockSqlUserManager struct { - sqlUsers []MockSqlUserResource -} - -type MockSqlUserResource struct { - username string - roles []string - sqlDB *dbsql.DB -} - -func NewMockAzureSqlUserManager() *MockSqlUserManager { - return &MockSqlUserManager{} -} - -func findSqlUser(res []MockSqlUserResource, predicate func(MockSqlUserResource) bool) (int, MockSqlUserResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, MockSqlUserResource{} -} - -func (manager *MockSqlUserManager) ConnectToSqlDb(ctx context.Context, drivername string, server string, dbname string, port int, username string, password string) (*sql.DB, error) { - db := &sql.DB{} - return db, nil -} - -func (manager *MockSqlUserManager) CreateUser(ctx context.Context, secret map[string][]byte, db *dbsql.DB) (string, error) { - newUser := string(secret[azuresqluser.SecretUsernameKey]) - - q := MockSqlUserResource{ - username: newUser, - roles: []string{}, - sqlDB: db, - } - - manager.sqlUsers = append(manager.sqlUsers, q) - - return newUser, nil -} - -func (manager *MockSqlUserManager) DropUser(ctx context.Context, db *sql.DB, user string) error { - sqlUsers := manager.sqlUsers - - index, _ := findSqlUser(manager.sqlUsers, func(s MockSqlUserResource) bool { - return s.username == user - }) - - if index == -1 { - return errors.New("Sql User Not Found") - } - - manager.sqlUsers = append(sqlUsers[:index], sqlUsers[index+1:]...) - - return nil -} - -func (manager *MockSqlUserManager) UserExists(ctx context.Context, db *sql.DB, username string) (bool, error) { - - index, _ := findSqlUser(manager.sqlUsers, func(s MockSqlUserResource) bool { - return s.username == username - }) - - if index == -1 { - return false, errors.New("Sql User Not Found") - } - - return true, nil -} - -func (manager *MockSqlUserManager) GrantUserRoles(ctx context.Context, user string, roles []string, db *sql.DB) error { - - index, _ := findSqlUser(manager.sqlUsers, func(s MockSqlUserResource) bool { - return s.username == user - }) - - if index == -1 { - return errors.New("Sql User Not Found") - } - - manager.sqlUsers[index].roles = roles - - return nil -} - -func (s *MockSqlUserManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - return true, nil -} - -func (s *MockSqlUserManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - return true, nil -} - -func (s *MockSqlUserManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} - -func (s *MockSqlUserManager) convert(obj runtime.Object) (*v1alpha1.AzureSQLUser, error) { - local, ok := obj.(*v1alpha1.AzureSQLUser) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/eventhubs/consumergroup.go b/pkg/resourcemanager/mock/eventhubs/consumergroup.go deleted file mode 100644 index a77ba263888..00000000000 --- a/pkg/resourcemanager/mock/eventhubs/consumergroup.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package eventhubs - -import ( - "context" - "errors" - "fmt" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/eventhub/mgmt/2017-04-01/eventhub" - "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" -) - -type consumerGroupResource struct { - resourceGroupName string - namespaceName string - eventHubName string - consumerGroupName string - ConsumerGroup eventhub.ConsumerGroup -} - -type mockConsumerGroupManager struct { - consumerGroupResources []consumerGroupResource -} - -func NewMockConsumerGroupClient() *mockConsumerGroupManager { - return &mockConsumerGroupManager{} -} - -func findConsumerGroup(res []consumerGroupResource, predicate func(consumerGroupResource) bool) (int, consumerGroupResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, consumerGroupResource{} -} - -func find(res []interface{}, predicate func(interface{}) bool) (int, interface{}) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, consumerGroupResource{} -} - -func (manager *mockConsumerGroupManager) CreateConsumerGroup(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, consumerGroupName string) (eventhub.ConsumerGroup, error) { - var consumerGroup = eventhub.ConsumerGroup{ - Response: helpers.GetRestResponse(201), - Name: to.StringPtr(consumerGroupName), - } - manager.consumerGroupResources = append(manager.consumerGroupResources, consumerGroupResource{ - resourceGroupName: resourceGroupName, - namespaceName: namespaceName, - eventHubName: eventHubName, - consumerGroupName: consumerGroupName, - ConsumerGroup: consumerGroup, - }) - return consumerGroup, nil -} - -func (manager *mockConsumerGroupManager) DeleteConsumerGroup(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, consumerGroupName string) (autorest.Response, error) { - groups := manager.consumerGroupResources - - index, _ := findConsumerGroup(groups, func(g consumerGroupResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName && - g.eventHubName == eventHubName && - g.consumerGroupName == consumerGroupName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("consumer group not found") - } - - manager.consumerGroupResources = append(groups[:index], groups[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -func (manager *mockConsumerGroupManager) GetConsumerGroup(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, consumerGroupName string) (eventhub.ConsumerGroup, error) { - groups := manager.consumerGroupResources - - index, group := findConsumerGroup(groups, func(g consumerGroupResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName && - g.eventHubName == eventHubName && - g.consumerGroupName == consumerGroupName - }) - - if index == -1 { - return eventhub.ConsumerGroup{ - Response: helpers.GetRestResponse(http.StatusNotFound), - }, errors.New("consumer group not found") - } - - group.ConsumerGroup.Response = helpers.GetRestResponse(http.StatusOK) - return group.ConsumerGroup, nil -} - -func (cg *mockConsumerGroupManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := cg.convert(obj) - if err != nil { - return false, err - } - - // write information back to instance - instance.Status.Provisioning = true - - kubeObjectName := instance.Name - namespaceName := instance.Spec.Namespace - resourcegroup := instance.Spec.ResourceGroup - eventhubName := instance.Spec.Eventhub - azureConsumerGroupName := instance.Spec.ConsumerGroupName - - // if no need for shared consumer group name, use the kube name - if len(azureConsumerGroupName) == 0 { - azureConsumerGroupName = kubeObjectName - } - - resp, err := cg.CreateConsumerGroup(ctx, resourcegroup, namespaceName, eventhubName, azureConsumerGroupName) - if err != nil { - instance.Status.Message = err.Error() - instance.Status.Provisioning = false - return false, err - } - instance.Status.State = resp.Status - instance.Status.Message = "success" - // write information back to instance - instance.Status.Provisioning = false - instance.Status.Provisioned = true - - return true, nil -} - -func (cg *mockConsumerGroupManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := cg.convert(obj) - if err != nil { - return false, err - } - - kubeObjectName := instance.Name - namespaceName := instance.Spec.Namespace - resourcegroup := instance.Spec.ResourceGroup - eventhubName := instance.Spec.Eventhub - azureConsumerGroupName := instance.Spec.ConsumerGroupName - - // if no need for shared consumer group name, use the kube name - if len(azureConsumerGroupName) == 0 { - azureConsumerGroupName = kubeObjectName - } - - _, err = cg.DeleteConsumerGroup(ctx, resourcegroup, namespaceName, eventhubName, azureConsumerGroupName) - if err != nil { - return false, err - } - - instance.Status.Message = "deleted" - - return true, nil -} - -func (cg *mockConsumerGroupManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - - instance, err := cg.convert(obj) - if err != nil { - return nil, err - } - - return []resourcemanager.KubeParent{ - { - Key: types.NamespacedName{ - Namespace: instance.Namespace, - Name: instance.Spec.Namespace, - }, - Target: &v1alpha1.EventhubNamespace{}, - }, - { - Key: types.NamespacedName{ - Namespace: instance.Namespace, - Name: instance.Spec.ResourceGroup, - }, - Target: &v1alpha1.ResourceGroup{}, - }, - }, nil -} - -func (g *mockConsumerGroupManager) GetStatus(obj runtime.Object) (*v1alpha1.ASOStatus, error) { - instance, err := g.convert(obj) - if err != nil { - return nil, err - } - return &instance.Status, nil -} - -func (cg *mockConsumerGroupManager) convert(obj runtime.Object) (*v1alpha1.ConsumerGroup, error) { - local, ok := obj.(*v1alpha1.ConsumerGroup) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/eventhubs/hub.go b/pkg/resourcemanager/mock/eventhubs/hub.go deleted file mode 100644 index 75b711679d1..00000000000 --- a/pkg/resourcemanager/mock/eventhubs/hub.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package eventhubs - -import ( - "context" - "errors" - "fmt" - "net/http" - - "github.com/Azure/azure-service-operator/api/v1alpha1" - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - - "github.com/Azure/azure-sdk-for-go/services/eventhub/mgmt/2017-04-01/eventhub" - pkghelpers "github.com/Azure/azure-service-operator/pkg/helpers" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/config" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/azure-service-operator/pkg/secrets" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" -) - -type eventHubAccess struct { - rule eventhub.AuthorizationRule - keys eventhub.AccessKeys -} - -type eventHubResource struct { - resourceGroupName string - namespaceName string - eventHubName string - eventHub eventhub.Model - eventHubAccesses []eventHubAccess -} - -func findEventHub(res []eventHubResource, predicate func(eventHubResource) bool) (int, eventHubResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, eventHubResource{} -} - -func findAccess(res []eventHubAccess, name string) (int, eventHubAccess) { - for index, r := range res { - if *r.rule.Name == name { - return index, r - } - } - return -1, eventHubAccess{} -} - -type mockEventHubManager struct { - eventHubResources []eventHubResource - SecretClient secrets.SecretClient - Scheme *runtime.Scheme -} - -func NewMockEventHubClient(secretClient secrets.SecretClient, scheme *runtime.Scheme) *mockEventHubManager { - return &mockEventHubManager{ - SecretClient: secretClient, - Scheme: scheme, - eventHubResources: []eventHubResource{}, - } -} - -func (manager *mockEventHubManager) DeleteHub(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string) (result autorest.Response, err error) { - hubs := manager.eventHubResources - - index, _ := findEventHub(hubs, func(g eventHubResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName && - g.eventHubName == eventHubName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("eventhub not found") - } - - manager.eventHubResources = append(hubs[:index], hubs[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -func (manager *mockEventHubManager) CreateHub(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, messageRetentionInDays int32, partitionCount int32, captureDescription *eventhub.CaptureDescription) (eventhub.Model, error) { - - var eventHub = eventhub.Model{ - Response: helpers.GetRestResponse(201), - Properties: &eventhub.Properties{ - MessageRetentionInDays: to.Int64Ptr(int64(messageRetentionInDays)), - PartitionCount: to.Int64Ptr(int64(partitionCount)), - Status: "", - CaptureDescription: captureDescription, - }, - Name: &eventHubName, - } - manager.eventHubResources = append(manager.eventHubResources, eventHubResource{ - resourceGroupName: resourceGroupName, - namespaceName: namespaceName, - eventHubName: eventHubName, - eventHub: eventHub, - eventHubAccesses: []eventHubAccess{}, - }) - - return eventHub, nil -} - -func (manager *mockEventHubManager) GetHub(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string) (eventhub.Model, error) { - hubs := manager.eventHubResources - - index, hub := findEventHub(hubs, func(g eventHubResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName && - g.eventHubName == eventHubName - }) - - if index == -1 { - return eventhub.Model{}, errors.New("eventhub not found") - } - - return hub.eventHub, nil -} - -func (manager *mockEventHubManager) getHubAccess(resourceGroupName string, namespaceName string, eventHubName string, authorizationRuleName string) (eventHubResource, int, eventHubAccess, error) { - hubs := manager.eventHubResources - hubIndex, hub := findEventHub(hubs, func(g eventHubResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName && - g.eventHubName == eventHubName - }) - if hubIndex == -1 { - return eventHubResource{}, 0, eventHubAccess{}, errors.New("eventhub not found") - } - authRules := hub.eventHubAccesses - ruleIndex, rule := findAccess(authRules, authorizationRuleName) - - return hub, ruleIndex, rule, nil -} - -func (manager *mockEventHubManager) CreateOrUpdateAuthorizationRule(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, authorizationRuleName string, parameters eventhub.AuthorizationRule) (eventhub.AuthorizationRule, error) { - hub, accessIndex, _, err := manager.getHubAccess(resourceGroupName, namespaceName, eventHubName, authorizationRuleName) - if err != nil { - return eventhub.AuthorizationRule{}, err - } - - if accessIndex == -1 { - hub.eventHubAccesses = append(hub.eventHubAccesses, eventHubAccess{ - rule: parameters, - keys: eventhub.AccessKeys{ - Response: helpers.GetRestResponse(http.StatusOK), - PrimaryConnectionString: to.StringPtr(pkghelpers.RandomString(40)), - SecondaryConnectionString: to.StringPtr(pkghelpers.RandomString(40)), - AliasPrimaryConnectionString: to.StringPtr(pkghelpers.RandomString(40)), - AliasSecondaryConnectionString: to.StringPtr(pkghelpers.RandomString(40)), - PrimaryKey: to.StringPtr(pkghelpers.RandomString(15)), - SecondaryKey: to.StringPtr(pkghelpers.RandomString(15)), - KeyName: to.StringPtr(pkghelpers.RandomString(10)), - }, - }) - } else { - hub.eventHubAccesses[accessIndex].rule = parameters - } - - return parameters, nil -} - -func (manager *mockEventHubManager) ListKeys(ctx context.Context, resourceGroupName string, namespaceName string, eventHubName string, authorizationRuleName string) (eventhub.AccessKeys, error) { - _, accessIndex, access, err := manager.getHubAccess(resourceGroupName, namespaceName, eventHubName, authorizationRuleName) - - if err != nil { - return eventhub.AccessKeys{}, err - } - - if accessIndex == -1 { - return eventhub.AccessKeys{}, errors.New("eventhub access rule not found") - } - - return access.keys, nil -} - -func (e *mockEventHubManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := e.convert(obj) - if err != nil { - return false, err - } - - eventhubName := instance.ObjectMeta.Name - eventhubNamespace := instance.Spec.Namespace - resourcegroup := instance.Spec.ResourceGroup - partitionCount := instance.Spec.Properties.PartitionCount - messageRetentionInDays := instance.Spec.Properties.MessageRetentionInDays - secretName := instance.Spec.SecretName - captureDescription := instance.Spec.Properties.CaptureDescription - - if len(secretName) == 0 { - secretName = eventhubName - instance.Spec.SecretName = eventhubName - } - - // write information back to instance - instance.Status.Provisioning = true - - capturePtr := getCaptureDescriptionPtr(captureDescription) - - _, err = e.CreateHub(ctx, resourcegroup, eventhubNamespace, eventhubName, messageRetentionInDays, partitionCount, capturePtr) - if err != nil { - instance.Status.Provisioning = false - return false, err - } - - // write information back to instance - instance.Status.Provisioning = false - instance.Status.Provisioned = true - - return true, nil -} - -func (e *mockEventHubManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := e.convert(obj) - if err != nil { - return false, err - } - - eventhubName := instance.ObjectMeta.Name - eventhubNamespace := instance.Spec.Namespace - resourcegroup := instance.Spec.ResourceGroup - _, err = e.DeleteHub(ctx, resourcegroup, eventhubNamespace, eventhubName) - - return true, err -} - -func (e *mockEventHubManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} - -func (g *mockEventHubManager) GetStatus(obj runtime.Object) (*v1alpha1.ASOStatus, error) { - instance, err := g.convert(obj) - if err != nil { - return nil, err - } - return &instance.Status, nil -} - -func (e *mockEventHubManager) convert(obj runtime.Object) (*azurev1alpha1.Eventhub, error) { - local, ok := obj.(*azurev1alpha1.Eventhub) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} - -const storageAccountResourceFmt = "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s" - -func getCaptureDescriptionPtr(captureDescription azurev1alpha1.CaptureDescription) *eventhub.CaptureDescription { - // add capture details - var capturePtr *eventhub.CaptureDescription - - storage := captureDescription.Destination.StorageAccount - storageAccountResourceID := fmt.Sprintf(storageAccountResourceFmt, config.SubscriptionID(), storage.ResourceGroup, storage.AccountName) - - if captureDescription.Enabled { - capturePtr = &eventhub.CaptureDescription{ - Enabled: to.BoolPtr(true), - Encoding: eventhub.Avro, - IntervalInSeconds: &captureDescription.IntervalInSeconds, - SizeLimitInBytes: &captureDescription.SizeLimitInBytes, - Destination: &eventhub.Destination{ - Name: &captureDescription.Destination.Name, - DestinationProperties: &eventhub.DestinationProperties{ - StorageAccountResourceID: &storageAccountResourceID, - BlobContainer: &captureDescription.Destination.BlobContainer, - ArchiveNameFormat: &captureDescription.Destination.ArchiveNameFormat, - }, - }, - SkipEmptyArchives: to.BoolPtr(true), - } - } - return capturePtr -} diff --git a/pkg/resourcemanager/mock/eventhubs/managers.go b/pkg/resourcemanager/mock/eventhubs/managers.go deleted file mode 100644 index fd4414211b8..00000000000 --- a/pkg/resourcemanager/mock/eventhubs/managers.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package eventhubs - -import . "github.com/Azure/azure-service-operator/pkg/resourcemanager/eventhubs" - -var MockEventHubManagers = EventHubManagers{ - EventHubNamespace: &mockEventHubNamespaceManager{}, - EventHub: &mockEventHubManager{}, - ConsumerGroup: &mockConsumerGroupManager{}, -} diff --git a/pkg/resourcemanager/mock/eventhubs/namespace.go b/pkg/resourcemanager/mock/eventhubs/namespace.go deleted file mode 100644 index ee835018d83..00000000000 --- a/pkg/resourcemanager/mock/eventhubs/namespace.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package eventhubs - -import ( - "context" - "errors" - "fmt" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/eventhub/mgmt/2017-04-01/eventhub" - "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/errhelp" - apphelpers "github.com/Azure/azure-service-operator/pkg/helpers" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" -) - -type eventHubNamespaceResource struct { - resourceGroupName string - namespaceName string - eHNamespace eventhub.EHNamespace -} - -type mockEventHubNamespaceManager struct { - eventHubNamespaceResources []eventHubNamespaceResource -} - -func NewMockEventHubNamespaceClient() *mockEventHubNamespaceManager { - return &mockEventHubNamespaceManager{} -} - -func findEventHubNamespace(res []eventHubNamespaceResource, predicate func(eventHubNamespaceResource) bool) (int, eventHubNamespaceResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, eventHubNamespaceResource{} -} - -func (manager *mockEventHubNamespaceManager) CreateNamespaceAndWait(ctx context.Context, resourceGroupName string, namespaceName string, location string) (*eventhub.EHNamespace, error) { - var eventHubNamespace = eventhub.EHNamespace{ - Response: helpers.GetRestResponse(201), - EHNamespaceProperties: &eventhub.EHNamespaceProperties{ - ProvisioningState: to.StringPtr("Succeeded"), - }, - Location: &location, - Name: to.StringPtr(namespaceName), - } - manager.eventHubNamespaceResources = append(manager.eventHubNamespaceResources, eventHubNamespaceResource{ - resourceGroupName: resourceGroupName, - namespaceName: namespaceName, - eHNamespace: eventHubNamespace, - }) - return &eventHubNamespace, nil -} - -func (manager *mockEventHubNamespaceManager) CreateNamespace(ctx context.Context, resourceGroupName string, namespaceName string, location string) (*eventhub.EHNamespace, error) { - var eventHubNamespace = eventhub.EHNamespace{ - Response: helpers.GetRestResponse(201), - EHNamespaceProperties: &eventhub.EHNamespaceProperties{ - ProvisioningState: to.StringPtr("Succeeded"), - }, - Location: &location, - Name: to.StringPtr(namespaceName), - } - manager.eventHubNamespaceResources = append(manager.eventHubNamespaceResources, eventHubNamespaceResource{ - resourceGroupName: resourceGroupName, - namespaceName: namespaceName, - eHNamespace: eventHubNamespace, - }) - return &eventHubNamespace, nil -} - -func (manager *mockEventHubNamespaceManager) DeleteNamespace(ctx context.Context, resourceGroupName string, namespaceName string) (autorest.Response, error) { - namespaces := manager.eventHubNamespaceResources - - index, _ := findEventHubNamespace(namespaces, func(g eventHubNamespaceResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("eventhub namespace not found") - } - - manager.eventHubNamespaceResources = append(namespaces[:index], namespaces[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -func (manager *mockEventHubNamespaceManager) GetNamespace(ctx context.Context, resourceGroupName string, namespaceName string) (*eventhub.EHNamespace, error) { - groups := manager.eventHubNamespaceResources - - index, group := findEventHubNamespace(groups, func(g eventHubNamespaceResource) bool { - return g.resourceGroupName == resourceGroupName && - g.namespaceName == namespaceName - }) - - if index == -1 { - return &eventhub.EHNamespace{}, errors.New("eventhub namespace not found") - } - - return &group.eHNamespace, nil -} - -func (ns *mockEventHubNamespaceManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := ns.convert(obj) - if err != nil { - return false, err - } - - namespaceLocation := instance.Spec.Location - namespaceName := instance.Name - resourcegroup := instance.Spec.ResourceGroup - - // write information back to instance - instance.Status.Provisioning = true - - // @todo handle updates - _, err = ns.GetNamespace(ctx, resourcegroup, namespaceName) - if err == nil { - instance.Status.Provisioning = false - instance.Status.Provisioned = true - - return true, nil - } - - // set this message so the tests are happy - if instance.Spec.ResourceGroup == "gone" { - instance.Status.Message = "ResourceGroupNotFound" - } - - // create Event Hubs namespace - _, err = ns.CreateNamespace(ctx, resourcegroup, namespaceName, namespaceLocation) - if err != nil { - catch := []string{ - errhelp.ResourceGroupNotFoundErrorCode, - errhelp.AsyncOpIncompleteError, - } - azerr := errhelp.NewAzureErrorAzureError(err) - if apphelpers.ContainsString(catch, azerr.Type) { - instance.Status.Message = err.Error() - return false, nil - } - - instance.Status.Provisioning = false - - return true, fmt.Errorf("EventhubNamespace create error %v", err) - - } - // write information back to instance - instance.Status.Provisioning = false - instance.Status.Provisioned = true - - return true, nil -} - -func (ns *mockEventHubNamespaceManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := ns.convert(obj) - if err != nil { - return false, err - } - - namespaceName := instance.Name - resourcegroup := instance.Spec.ResourceGroup - - _, err = ns.DeleteNamespace(ctx, resourcegroup, namespaceName) - if err != nil { - azerr := errhelp.NewAzureErrorAzureError(err) - - // check if async op from previous delete was still happening - catch := []string{ - errhelp.AsyncOpIncompleteError, - errhelp.RequestConflictError, - } - if apphelpers.ContainsString(catch, azerr.Type) { - return true, nil - } - - // check if namespace was already gone - catch = []string{ - errhelp.NotFoundErrorCode, - } - if apphelpers.ContainsString(catch, azerr.Type) { - return false, nil - } - - // some error we don't know about or can't handle happened - instance.Status.Provisioning = false - - return true, fmt.Errorf("EventhubNamespace delete error %v", err) - - } - - return false, nil -} - -func (ns *mockEventHubNamespaceManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - - instance, err := ns.convert(obj) - if err != nil { - return nil, err - } - - key := types.NamespacedName{Namespace: instance.Namespace, Name: instance.Spec.ResourceGroup} - - return []resourcemanager.KubeParent{ - {Key: key, Target: &v1alpha1.ResourceGroup{}}, - }, nil -} - -func (g *mockEventHubNamespaceManager) GetStatus(obj runtime.Object) (*v1alpha1.ASOStatus, error) { - instance, err := g.convert(obj) - if err != nil { - return nil, err - } - return &instance.Status, nil -} - -func (ns *mockEventHubNamespaceManager) convert(obj runtime.Object) (*v1alpha1.EventhubNamespace, error) { - local, ok := obj.(*v1alpha1.EventhubNamespace) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/helpers/helpers.go b/pkg/resourcemanager/mock/helpers/helpers.go deleted file mode 100644 index 0c2238a50ae..00000000000 --- a/pkg/resourcemanager/mock/helpers/helpers.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package helpers - -import ( - "fmt" - "github.com/Azure/go-autorest/autorest" - "net/http" -) - -func GetRestResponse(statusCode int) autorest.Response { - return autorest.Response{ - Response: &http.Response{ - Status: fmt.Sprintf("%d", statusCode), - StatusCode: statusCode, - }, - } -} diff --git a/pkg/resourcemanager/mock/keyvaults/keyvault.go b/pkg/resourcemanager/mock/keyvaults/keyvault.go deleted file mode 100644 index 7158422549d..00000000000 --- a/pkg/resourcemanager/mock/keyvaults/keyvault.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package keyvaults - -import ( - "context" - "errors" - "fmt" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2018-02-14/keyvault" - "github.com/Azure/azure-service-operator/api/v1alpha1" - pkghelpers "github.com/Azure/azure-service-operator/pkg/helpers" - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" - "k8s.io/apimachinery/pkg/runtime" -) - -type keyVaultResource struct { - resourceGroupName string - vaultName string - KeyVault keyvault.Vault -} - -type MockKeyVaultManager struct { - keyVaultResources []keyVaultResource -} - -func findKeyVault(res []keyVaultResource, predicate func(keyVaultResource) bool) (int, keyVaultResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, keyVaultResource{} -} - -// CreateVault creates a new key vault -func (manager *MockKeyVaultManager) CreateVault(ctx context.Context, instance *v1alpha1.KeyVault, tags map[string]*string) (keyvault.Vault, error) { - vaultName := instance.Name - groupName := instance.Spec.ResourceGroup - location := instance.Spec.Location - - v := keyvault.Vault{ - Response: helpers.GetRestResponse(http.StatusOK), - Properties: &keyvault.VaultProperties{}, - ID: to.StringPtr(pkghelpers.RandomString(10)), - Name: to.StringPtr(vaultName), - Location: to.StringPtr(location), - } - - _, err := manager.GetVault(ctx, groupName, vaultName) - if err != nil { - manager.keyVaultResources = append(manager.keyVaultResources, keyVaultResource{ - resourceGroupName: groupName, - vaultName: vaultName, - KeyVault: v, - }) - } - - return v, nil -} - -// CreateVaultWithAccessPolicies creates a new key vault -func (manager *MockKeyVaultManager) CreateVaultWithAccessPolicies(ctx context.Context, groupName string, vaultName string, location string, clientID string) (keyvault.Vault, error) { - v := keyvault.Vault{ - Response: helpers.GetRestResponse(http.StatusOK), - Properties: &keyvault.VaultProperties{}, - ID: to.StringPtr(pkghelpers.RandomString(10)), - Name: to.StringPtr(vaultName), - Location: to.StringPtr(location), - } - - _, err := manager.GetVault(ctx, groupName, vaultName) - if err != nil { - manager.keyVaultResources = append(manager.keyVaultResources, keyVaultResource{ - resourceGroupName: groupName, - vaultName: vaultName, - KeyVault: v, - }) - } - - return v, nil -} - -// DeleteVault removes the resource group named by env var -func (manager *MockKeyVaultManager) DeleteVault(ctx context.Context, groupName string, vaultName string) (result autorest.Response, err error) { - vaults := manager.keyVaultResources - - index, _ := findKeyVault(vaults, func(g keyVaultResource) bool { - return g.resourceGroupName == groupName && - g.vaultName == vaultName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("key vault not found") - } - - manager.keyVaultResources = append(vaults[:index], vaults[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -// Returns an existing keyvault instance -func (manager *MockKeyVaultManager) GetVault(ctx context.Context, groupName string, vaultName string) (result keyvault.Vault, err error) { - vaults := manager.keyVaultResources - - index, v := findKeyVault(vaults, func(g keyVaultResource) bool { - return g.resourceGroupName == groupName && - g.vaultName == vaultName - }) - - if index == -1 { - return keyvault.Vault{ - Response: helpers.GetRestResponse(http.StatusNotFound), - }, errors.New("key vault not found") - } - - return v.KeyVault, nil -} - -func (manager *MockKeyVaultManager) convert(obj runtime.Object) (*v1alpha1.KeyVault, error) { - local, ok := obj.(*v1alpha1.KeyVault) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} - -func (manager *MockKeyVaultManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - tags := map[string]*string{} - _, _ = manager.CreateVault( - ctx, - instance, - tags, - ) - - instance.Status.Provisioned = true - - return true, nil -} -func (manager *MockKeyVaultManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - _, _ = manager.DeleteVault(ctx, instance.Spec.ResourceGroup, instance.Name) - - return false, nil -} -func (manager *MockKeyVaultManager) GetParents(runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} diff --git a/pkg/resourcemanager/mock/psql/postgresqldatabase.go b/pkg/resourcemanager/mock/psql/postgresqldatabase.go deleted file mode 100644 index 50ea2ab9e24..00000000000 --- a/pkg/resourcemanager/mock/psql/postgresqldatabase.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package psql - -import ( - "context" - "errors" - "fmt" - "net/http" - - postgresql "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" - "github.com/Azure/azure-service-operator/api/v1alpha1" - resourcemanager "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest/to" - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" -) - -type MockPostgreSqlDbManager struct { - resourceGroupName string - PostgresqlDbs []MockPostgreSqlDbResource - Log logr.Logger -} - -type MockPostgreSqlDbResource struct { - resourceGroupName string - PostgresqlServerName string - PostgresqlDb postgresql.Database -} - -func NewMockPostgreSqlDbManager(log logr.Logger) *MockPostgreSqlDbManager { - return &MockPostgreSqlDbManager{ - Log: log, - } -} - -func findPostgreSqlDb(res []MockPostgreSqlDbResource, predicate func(MockPostgreSqlDbResource) bool) (int, error) { - for index, r := range res { - if predicate(r) { - return index, nil - } - } - return -1, errors.New("not found") -} - -//CreateorUpdateDB creates a Postgresql Db -func (manager *MockPostgreSqlDbManager) CreateDatabaseIfValid(ctx context.Context, databasename string, servername string, resourcegroup string) (postgresql.DatabasesCreateOrUpdateFuture, error) { - index, _ := findPostgreSqlDb(manager.PostgresqlDbs, func(s MockPostgreSqlDbResource) bool { - return s.resourceGroupName == resourcegroup && s.PostgresqlServerName == servername && *s.PostgresqlDb.Name == databasename - }) - - PostgresqlD := postgresql.Database{ - Response: helpers.GetRestResponse(http.StatusCreated), - Name: to.StringPtr(databasename), - } - - q := MockPostgreSqlDbResource{ - resourceGroupName: resourcegroup, - PostgresqlServerName: servername, - PostgresqlDb: PostgresqlD, - } - - if index == -1 { - manager.PostgresqlDbs = append(manager.PostgresqlDbs, q) - } - - return postgresql.DatabasesCreateOrUpdateFuture{}, nil - -} - -func (manager *MockPostgreSqlDbManager) GetDatabase(ctx context.Context, resourcegroup string, servername string, database string) (postgresql.Database, error) { - index, _ := findPostgreSqlDb(manager.PostgresqlDbs, func(s MockPostgreSqlDbResource) bool { - return s.resourceGroupName == resourcegroup && s.PostgresqlServerName == servername && *s.PostgresqlDb.Name == database - }) - - if index == -1 { - return postgresql.Database{}, errors.New("Sql Db Not Found") - } - - return manager.PostgresqlDbs[index].PostgresqlDb, nil -} - -// DeleteDb removes the Postgresql db -func (manager *MockPostgreSqlDbManager) DeleteDatabase(ctx context.Context, databasename string, servername string, resourcegroup string) (string, error) { - PostgresqlDbs := manager.PostgresqlDbs - - index, _ := findPostgreSqlDb(manager.PostgresqlDbs, func(s MockPostgreSqlDbResource) bool { - return s.resourceGroupName == resourcegroup && s.PostgresqlServerName == servername && *s.PostgresqlDb.Name == databasename - }) - - if index == -1 { - return "Not found", nil - } - - manager.PostgresqlDbs = append(PostgresqlDbs[:index], PostgresqlDbs[index+1:]...) - - return "Deleted", nil -} - -func (manager *MockPostgreSqlDbManager) convert(obj runtime.Object) (*v1alpha1.PostgreSQLDatabase, error) { - local, ok := obj.(*v1alpha1.PostgreSQLDatabase) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} - -func (manager *MockPostgreSqlDbManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - _, _ = manager.CreateDatabaseIfValid(ctx, instance.Name, instance.Spec.Server, instance.Spec.ResourceGroup) - - instance.Status.Provisioned = true - - return true, nil -} - -func (manager *MockPostgreSqlDbManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - _, _ = manager.DeleteDatabase(ctx, instance.Name, instance.Spec.Server, instance.Spec.ResourceGroup) - - return false, nil -} - -func (manager *MockPostgreSqlDbManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} diff --git a/pkg/resourcemanager/mock/psql/postgresqlfirewallrule.go b/pkg/resourcemanager/mock/psql/postgresqlfirewallrule.go deleted file mode 100644 index 9e09275ddd1..00000000000 --- a/pkg/resourcemanager/mock/psql/postgresqlfirewallrule.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package psql - -import ( - "context" - "errors" - "fmt" - "net/http" - - postgresql "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" - "github.com/Azure/azure-service-operator/api/v1alpha1" - resourcemanager "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest/to" - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" -) - -type MockPostgreSqlFirewallRuleManager struct { - resourceGroupName string - PostgresqlFirewallRules []MockPostgreSqlFirewallRuleResource - Log logr.Logger -} - -type MockPostgreSqlFirewallRuleResource struct { - resourceGroupName string - PostgresqlServerName string - PostgresqlFirewallRule postgresql.FirewallRule -} - -func NewMockPostgreSqlFirewallRuleManager(log logr.Logger) *MockPostgreSqlFirewallRuleManager { - return &MockPostgreSqlFirewallRuleManager{ - Log: log, - } -} - -func findPostgreSqlFirewallRule(res []MockPostgreSqlFirewallRuleResource, predicate func(MockPostgreSqlFirewallRuleResource) bool) (int, error) { - for index, r := range res { - if predicate(r) { - return index, nil - } - } - return -1, errors.New("not found") -} - -//CreateorUpdateFirewallRule creates a Postgresql FirewallRule -func (manager *MockPostgreSqlFirewallRuleManager) CreateFirewallRule(ctx context.Context, resourcegroup string, servername string, firewallrulename string, startip string, endip string) (postgresql.FirewallRulesCreateOrUpdateFuture, error) { - index, _ := findPostgreSqlFirewallRule(manager.PostgresqlFirewallRules, func(s MockPostgreSqlFirewallRuleResource) bool { - return s.resourceGroupName == resourcegroup && s.PostgresqlServerName == servername && *s.PostgresqlFirewallRule.Name == firewallrulename - }) - - PostgresqlF := postgresql.FirewallRule{ - Response: helpers.GetRestResponse(http.StatusCreated), - Name: to.StringPtr(firewallrulename), - FirewallRuleProperties: &postgresql.FirewallRuleProperties{ - StartIPAddress: to.StringPtr(startip), - EndIPAddress: to.StringPtr(endip), - }, - } - - q := MockPostgreSqlFirewallRuleResource{ - resourceGroupName: resourcegroup, - PostgresqlServerName: servername, - PostgresqlFirewallRule: PostgresqlF, - } - - if index == -1 { - manager.PostgresqlFirewallRules = append(manager.PostgresqlFirewallRules, q) - } - - return postgresql.FirewallRulesCreateOrUpdateFuture{}, nil - -} - -func (manager *MockPostgreSqlFirewallRuleManager) GetFirewallRule(ctx context.Context, resourcegroup string, servername string, firewallrulename string) (postgresql.FirewallRule, error) { - index, _ := findPostgreSqlFirewallRule(manager.PostgresqlFirewallRules, func(s MockPostgreSqlFirewallRuleResource) bool { - return s.resourceGroupName == resourcegroup && s.PostgresqlServerName == servername && *s.PostgresqlFirewallRule.Name == firewallrulename - }) - - if index == -1 { - return postgresql.FirewallRule{}, errors.New("Sql Fw rule Not Found") - } - - return manager.PostgresqlFirewallRules[index].PostgresqlFirewallRule, nil -} - -// DeleteFirewallRule removes the Postgresql FirewallRule -func (manager *MockPostgreSqlFirewallRuleManager) DeleteFirewallRule(ctx context.Context, resourcegroup string, servername string, firewallrulename string) (string, error) { - PostgresqlFirewallRules := manager.PostgresqlFirewallRules - - index, _ := findPostgreSqlFirewallRule(manager.PostgresqlFirewallRules, func(s MockPostgreSqlFirewallRuleResource) bool { - return s.resourceGroupName == resourcegroup && s.PostgresqlServerName == servername && *s.PostgresqlFirewallRule.Name == firewallrulename - }) - - if index == -1 { - return "Not found", nil - } - - manager.PostgresqlFirewallRules = append(PostgresqlFirewallRules[:index], PostgresqlFirewallRules[index+1:]...) - - return "Deleted", nil -} - -func (manager *MockPostgreSqlFirewallRuleManager) convert(obj runtime.Object) (*v1alpha1.PostgreSQLFirewallRule, error) { - local, ok := obj.(*v1alpha1.PostgreSQLFirewallRule) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} - -func (manager *MockPostgreSqlFirewallRuleManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - _, _ = manager.CreateFirewallRule(ctx, instance.Spec.ResourceGroup, instance.Spec.Server, instance.Name, "0.0.0.0", "0.0.0.0") - - instance.Status.Provisioned = true - - return true, nil -} - -func (manager *MockPostgreSqlFirewallRuleManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - _, _ = manager.DeleteFirewallRule(ctx, instance.Spec.ResourceGroup, instance.Spec.Server, instance.Name) - - return false, nil -} - -func (manager *MockPostgreSqlFirewallRuleManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} diff --git a/pkg/resourcemanager/mock/psql/postgresqlserver.go b/pkg/resourcemanager/mock/psql/postgresqlserver.go deleted file mode 100644 index 14fbeaa66f6..00000000000 --- a/pkg/resourcemanager/mock/psql/postgresqlserver.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package psql - -import ( - "context" - "errors" - "fmt" - "net/http" - - postgresql "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" - "github.com/Azure/azure-service-operator/api/v1alpha1" - resourcemanager "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/azure-service-operator/pkg/secrets" - "github.com/Azure/go-autorest/autorest/to" - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" -) - -type MockPostgreSqlServerManager struct { - resourceGroupName string - PostgresqlServers []MockPostgreSqlServerResource - SecretClient secrets.SecretClient - Scheme *runtime.Scheme - Log logr.Logger -} - -type MockPostgreSqlServerResource struct { - resourceGroupName string - PostgresqlServer postgresql.Server -} - -func NewMockPSQLServerClient(log logr.Logger, secretclient secrets.SecretClient, scheme *runtime.Scheme) *MockPostgreSqlServerManager { - return &MockPostgreSqlServerManager{ - Log: log, - SecretClient: secretclient, - Scheme: scheme, - } -} - -func findPostgreSqlServer(res []MockPostgreSqlServerResource, predicate func(MockPostgreSqlServerResource) bool) (int, error) { - for index, r := range res { - if predicate(r) { - return index, nil - } - } - return -1, errors.New("not found") -} - -// CreateServerIfValid creates a new Postgresql server -func (manager *MockPostgreSqlServerManager) CreateServerIfValid(ctx context.Context, servername string, resourcegroup string, location string, tags map[string]*string, serverversion postgresql.ServerVersion, sslenforcement postgresql.SslEnforcementEnum, skuInfo postgresql.Sku, adminlogin string, adminpassword string) (postgresql.ServersCreateFuture, error) { - index, _ := findPostgreSqlServer(manager.PostgresqlServers, func(s MockPostgreSqlServerResource) bool { - return s.resourceGroupName == resourcegroup && *s.PostgresqlServer.Name == servername - }) - - postgresqlS := postgresql.Server{ - Response: helpers.GetRestResponse(http.StatusCreated), - Location: to.StringPtr(location), - Name: to.StringPtr(servername), - } - - q := MockPostgreSqlServerResource{ - resourceGroupName: resourcegroup, - PostgresqlServer: postgresqlS, - } - - if index == -1 { - manager.PostgresqlServers = append(manager.PostgresqlServers, q) - } - - f := postgresql.ServersCreateFuture{} - - return f, nil -} - -// DeleteServer removes the postgresqlserver -func (manager *MockPostgreSqlServerManager) DeleteServer(ctx context.Context, resourcegroup string, servername string) (string, error) { - PostgresqlServers := manager.PostgresqlServers - - index, _ := findPostgreSqlServer(PostgresqlServers, func(s MockPostgreSqlServerResource) bool { - return s.resourceGroupName == resourcegroup && *s.PostgresqlServer.Name == servername - }) - - if index == -1 { - return "Not Found", nil - } - - manager.PostgresqlServers = append(PostgresqlServers[:index], PostgresqlServers[index+1:]...) - - return "Deleted", nil -} - -// GetServer gets a postgresql server -func (manager *MockPostgreSqlServerManager) GetServer(ctx context.Context, resourcegroup string, servername string) (postgresql.Server, error) { - index, _ := findPostgreSqlServer(manager.PostgresqlServers, func(s MockPostgreSqlServerResource) bool { - return s.resourceGroupName == resourcegroup && *s.PostgresqlServer.Name == servername - }) - - if index == -1 { - return postgresql.Server{}, errors.New("Sql Server Not Found") - } - - state := postgresql.ServerState("Ready") - serverProperties := postgresql.ServerProperties{UserVisibleState: state} - server := manager.PostgresqlServers[index].PostgresqlServer - server.ServerProperties = &serverProperties - - return server, nil -} - -func (manager *MockPostgreSqlServerManager) convert(obj runtime.Object) (*v1alpha1.PostgreSQLServer, error) { - local, ok := obj.(*v1alpha1.PostgreSQLServer) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} - -func (manager *MockPostgreSqlServerManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - tags := map[string]*string{} - _, _ = manager.CreateServerIfValid( - ctx, - instance.Name, - instance.Spec.ResourceGroup, - instance.Spec.Location, - tags, - postgresql.ServerVersion("10"), - postgresql.SslEnforcementEnumEnabled, - postgresql.Sku{}, - "", - "", - ) - - instance.Status.Provisioned = true - - return true, nil -} -func (manager *MockPostgreSqlServerManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - - instance, err := manager.convert(obj) - if err != nil { - return true, err - } - - _, _ = manager.DeleteServer(ctx, instance.Spec.ResourceGroup, instance.Name) - - return false, nil -} -func (manager *MockPostgreSqlServerManager) GetParents(runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} diff --git a/pkg/resourcemanager/mock/rediscaches/rediscaches.go b/pkg/resourcemanager/mock/rediscaches/rediscaches.go deleted file mode 100644 index 4f5883ab21e..00000000000 --- a/pkg/resourcemanager/mock/rediscaches/rediscaches.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -package rediscaches - -import ( - "context" - "errors" - "fmt" - "net/http" - - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - resourcemanager "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest/to" - - "github.com/Azure/azure-sdk-for-go/services/redis/mgmt/2018-03-01/redis" - "k8s.io/apimachinery/pkg/runtime" -) - -type redisCacheResource struct { - resourceGroupName string - redis redis.ResourceType -} - -type mockRedisCacheManager struct { - resourceGroupName string - redisCaches []redisCacheResource -} - -func NewMockRedisCacheManager() *mockRedisCacheManager { - return &mockRedisCacheManager{} -} - -func findRedisCache(res []redisCacheResource, predicate func(redisCacheResource) bool) (int, redisCacheResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, redisCacheResource{} -} - -func (manager *mockRedisCacheManager) CreateRedisCache(ctx context.Context, - groupName string, - redisCacheName string, - location string, - sku azurev1alpha1.RedisCacheSku, - enableNonSSLPort bool, - tags map[string]*string) (*redis.ResourceType, error) { - index, _ := findRedisCache(manager.redisCaches, func(s redisCacheResource) bool { - return s.resourceGroupName == groupName && *s.redis.Name == redisCacheName - }) - - rc := redis.ResourceType{ - Response: helpers.GetRestResponse(http.StatusCreated), - Location: to.StringPtr(location), - Name: to.StringPtr(redisCacheName), - } - - r := redisCacheResource{ - resourceGroupName: groupName, - redis: rc, - } - - if index == -1 { - manager.redisCaches = append(manager.redisCaches, r) - } - - return &r.redis, nil -} - -func (manager *mockRedisCacheManager) DeleteRedisCache(ctx context.Context, groupName string, redisCacheName string) (result redis.DeleteFuture, err error) { - redisCaches := manager.redisCaches - - index, _ := findRedisCache(redisCaches, func(s redisCacheResource) bool { - return s.resourceGroupName == groupName && - *s.redis.Name == redisCacheName - }) - - if index == -1 { - return redis.DeleteFuture{}, errors.New("Redis Cache Not Found") - } - - manager.redisCaches = append(redisCaches[:index], redisCaches[index+1:]...) - - return redis.DeleteFuture{}, nil -} - -func (manager *mockRedisCacheManager) convert(obj runtime.Object) (*azurev1alpha1.RedisCache, error) { - local, ok := obj.(*azurev1alpha1.RedisCache) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} - -func (manager *mockRedisCacheManager) Ensure(ctx context.Context, obj runtime.Object) (bool, error) { - instance, err := manager.convert(obj) - if err != nil { - return false, err - } - tags := map[string]*string{} - _, _ = manager.CreateRedisCache(ctx, instance.Spec.ResourceGroupName, instance.Name, instance.Spec.Location, instance.Spec.Properties.Sku, instance.Spec.Properties.EnableNonSslPort, tags) - - instance.Status.Provisioned = true - return true, nil - -} - -func (manager *mockRedisCacheManager) Delete(ctx context.Context, obj runtime.Object) (bool, error) { - instance, err := manager.convert(obj) - if err != nil { - return false, err - } - - _, _ = manager.DeleteRedisCache(ctx, instance.Spec.ResourceGroupName, instance.Name) - - return false, nil -} -func (manager *mockRedisCacheManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return []resourcemanager.KubeParent{}, nil -} diff --git a/pkg/resourcemanager/mock/resourcegroups/resourcegroup.go b/pkg/resourcemanager/mock/resourcegroups/resourcegroup.go deleted file mode 100644 index 2caaca55ce6..00000000000 --- a/pkg/resourcemanager/mock/resourcegroups/resourcegroup.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package resourcegroups - -import ( - "context" - "errors" - "fmt" - "net/http" - - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - - "github.com/Azure/azure-service-operator/pkg/resourcemanager" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "k8s.io/apimachinery/pkg/runtime" - - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2017-05-10/resources" - - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" -) - -type MockResourceGroupManager struct { - resourceGroups []resources.Group -} - -func findResourceGroup(res []resources.Group, predicate func(resources.Group) bool) (int, resources.Group) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, resources.Group{} -} - -// CreateGroup creates a new resource group -func (manager *MockResourceGroupManager) CreateGroup(ctx context.Context, groupName string, location string) (resources.Group, error) { - index, _ := findResourceGroup(manager.resourceGroups, func(g resources.Group) bool { - return *g.Name == groupName - }) - - r := resources.Group{ - Response: helpers.GetRestResponse(201), - Location: to.StringPtr(location), - Name: to.StringPtr(groupName), - } - - if index == -1 { - manager.resourceGroups = append(manager.resourceGroups, r) - } - - return r, nil -} - -// DeleteGroup removes the resource group -func (manager *MockResourceGroupManager) DeleteGroup(ctx context.Context, groupName string) (autorest.Response, error) { - groups := manager.resourceGroups - - index, _ := findResourceGroup(groups, func(g resources.Group) bool { - return *g.Name == groupName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("resource group not found") - } - - manager.resourceGroups = append(groups[:index], groups[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} - -func (manager *MockResourceGroupManager) DeleteGroupAsync(ctx context.Context, groupName string) (resources.GroupsDeleteFuture, error) { - _, err := manager.DeleteGroup(ctx, groupName) - - return resources.GroupsDeleteFuture{}, err -} - -func (manager *MockResourceGroupManager) CheckExistence(ctx context.Context, groupName string) (autorest.Response, error) { - groups := manager.resourceGroups - index, _ := findResourceGroup(groups, func(g resources.Group) bool { - return *g.Name == groupName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("resource group not found") - } - - return helpers.GetRestResponse(http.StatusNoContent), nil -} - -func (g *MockResourceGroupManager) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := g.convert(obj) - if err != nil { - return false, err - } - - _, err = g.CreateGroup(ctx, instance.ObjectMeta.Name, instance.Spec.Location) - if err != nil { - return false, err - } - - instance.Status.Provisioning = true - instance.Status.Provisioned = true - - return true, nil -} - -func (g *MockResourceGroupManager) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { - instance, err := g.convert(obj) - if err != nil { - return false, err - } - - _, err = g.DeleteGroup(ctx, instance.ObjectMeta.Name) - if err != nil { - return false, err - } - - return false, nil -} - -func (g *MockResourceGroupManager) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { - return nil, nil -} - -func (g *MockResourceGroupManager) convert(obj runtime.Object) (*azurev1alpha1.ResourceGroup, error) { - local, ok := obj.(*azurev1alpha1.ResourceGroup) - if !ok { - return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) - } - return local, nil -} diff --git a/pkg/resourcemanager/mock/sqlclient/sqlclient_gosdk.go b/pkg/resourcemanager/mock/sqlclient/sqlclient_gosdk.go deleted file mode 100644 index c3adc758b08..00000000000 --- a/pkg/resourcemanager/mock/sqlclient/sqlclient_gosdk.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package azuresql - -import ( - "context" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2015-05-01-preview/sql" - azuresqlshared "github.com/Azure/azure-service-operator/pkg/resourcemanager/azuresql/azuresqlshared" - helpers "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" -) - -// MockGoSDKClient struct -type MockGoSDKClient struct { - Server sql.Server - Database sql.Database - FirewallRule sql.FirewallRule - FailoverGroup sql.FailoverGroup - DatabasesCreateOrUpdateFuture sql.DatabasesCreateOrUpdateFuture - FailoverGroupsCreateOrUpdateFuture sql.FailoverGroupsCreateOrUpdateFuture -} - -// CreateOrUpdateSQLServer creates a new sql server -func (sdk *MockGoSDKClient) CreateOrUpdateSQLServer(ctx context.Context, resourceGroupName string, location string, serverName string, tags map[string]*string, properties azuresqlshared.SQLServerProperties, forceUpdate bool) (result sql.Server, err error) { - var sqlServer = sql.Server{ - Response: helpers.GetRestResponse(http.StatusCreated), - } - - sdk.Server = sqlServer - - return sqlServer, nil -} - -//DeleteSQLServer return StatusOK -func (sdk *MockGoSDKClient) DeleteSQLServer(ctx context.Context, resourceGroupName string, serverName string) (result autorest.Response, err error) { - - return helpers.GetRestResponse(http.StatusOK), nil -} - -//GetServer get server -func (sdk *MockGoSDKClient) GetServer(ctx context.Context, resourceGroupName string, serverName string) (result sql.Server, err error) { - - state := "Ready" - serverProperties := sql.ServerProperties{State: &state} - var sqlServer = sql.Server{ - Response: helpers.GetRestResponse(http.StatusCreated), - ServerProperties: &serverProperties, - } - - sdk.Server = sqlServer - - return sqlServer, nil -} - -//CreateOrUpdateSQLFirewallRule create or -func (sdk *MockGoSDKClient) CreateOrUpdateSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string, startIP string, endIP string) (result bool, err error) { - - return true, nil -} - -//DeleteSQLFirewallRule delete sql firewall -func (sdk *MockGoSDKClient) DeleteSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (err error) { - return nil -} - -//DeleteDB delete database -func (sdk *MockGoSDKClient) DeleteDB(ctx context.Context, resourceGroupName string, serverName string, databaseName string) (result autorest.Response, err error) { - - return helpers.GetRestResponse(http.StatusOK), nil -} - -//GetSQLFirewallRule get sql firewall rule -func (sdk *MockGoSDKClient) GetSQLFirewallRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (result sql.FirewallRule, err error) { - - var sqlFirewallRule = sql.FirewallRule{ - Response: helpers.GetRestResponse(http.StatusCreated), - } - - sdk.FirewallRule = sqlFirewallRule - - return sqlFirewallRule, nil -} - -//GetDB get database -func (sdk *MockGoSDKClient) GetDB(ctx context.Context, resourceGroupName string, serverName string, databaseName string) (sql.Database, error) { - - var sqlDatabase = sql.Database{ - Response: helpers.GetRestResponse(http.StatusCreated), - } - - sdk.Database = sqlDatabase - - return sqlDatabase, nil -} - -//CreateOrUpdateDB create or update DB -func (sdk *MockGoSDKClient) CreateOrUpdateDB(ctx context.Context, resourceGroupName string, location string, serverName string, tags map[string]*string, properties azuresqlshared.SQLDatabaseProperties) (sql.DatabasesCreateOrUpdateFuture, error) { - - var sqlDatabasesCreateOrUpdateFuture = sql.DatabasesCreateOrUpdateFuture{} - - return sqlDatabasesCreateOrUpdateFuture, nil -} - -//CreateOrUpdateFailoverGroup create or update failover group -func (sdk *MockGoSDKClient) CreateOrUpdateFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failovergroupname string, properties azuresqlshared.SQLFailoverGroupProperties) (result sql.FailoverGroupsCreateOrUpdateFuture, err error) { - - var sqlFailoverGroupsCreateOrUpdateFuture = sql.FailoverGroupsCreateOrUpdateFuture{} - sdk.FailoverGroupsCreateOrUpdateFuture = sqlFailoverGroupsCreateOrUpdateFuture - - return sqlFailoverGroupsCreateOrUpdateFuture, nil - -} - -//DeleteFailoverGroup delete fail over group -func (sdk *MockGoSDKClient) DeleteFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failoverGroupName string) (result autorest.Response, err error) { - - return helpers.GetRestResponse(http.StatusOK), nil -} - -//DeleteFailoverGroup delete fail over group -func (sdk *MockGoSDKClient) GetFailoverGroup(ctx context.Context, resourceGroupName string, serverName string, failovergroupname string) (sql.FailoverGroup, error) { - var sqlFailovergroup = sql.FailoverGroup{ - Response: helpers.GetRestResponse(http.StatusCreated), - } - - sdk.FailoverGroup = sqlFailovergroup - - return sqlFailovergroup, nil -} diff --git a/pkg/resourcemanager/mock/storages/blob_container.go b/pkg/resourcemanager/mock/storages/blob_container.go deleted file mode 100644 index ca04f55268e..00000000000 --- a/pkg/resourcemanager/mock/storages/blob_container.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package storages - -import ( - "context" - "errors" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" -) - -type blobContainerResource struct { - resourceGroupName string - storageAccountName string - blobContainerName string - accessLevel storage.PublicAccess - blobContainer storage.BlobContainer -} - -type mockBlobContainerManager struct { - blobContainerResource []blobContainerResource -} - -func findBlobContainer(res []blobContainerResource, predicate func(blobContainerResource) bool) (int, blobContainerResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, blobContainerResource{} -} - -// Creates a blob container in a storage account. -// Parameters: -// resourceGroupName - name of the resource group within the azure subscription. -// accountName - the name of the storage account -// containerName - the name of the container -func (manager *mockBlobContainerManager) CreateBlobContainer(ctx context.Context, resourceGroupName string, accountName string, containerName string, accessLevel storage.PublicAccess) (*storage.BlobContainer, error) { - bc := blobContainerResource{ - resourceGroupName: resourceGroupName, - storageAccountName: accountName, - blobContainerName: containerName, - blobContainer: storage.BlobContainer{}, - } - manager.blobContainerResource = append(manager.blobContainerResource, bc) - return &bc.blobContainer, nil -} - -// Get gets the description of the specified blob container. -// Parameters: -// resourceGroupName - name of the resource group within the azure subscription. -// accountName - the name of the storage account -// containerName - the name of the container -func (manager *mockBlobContainerManager) GetBlobContainer(ctx context.Context, resourceGroupName string, accountName string, containerName string) (storage.BlobContainer, error) { - containers := manager.blobContainerResource - - index, c := findBlobContainer(containers, func(g blobContainerResource) bool { - return g.resourceGroupName == resourceGroupName && - g.storageAccountName == accountName && - g.blobContainerName == containerName - }) - - if index == -1 { - return storage.BlobContainer{}, errors.New("blob container not found") - } - - return c.blobContainer, nil -} - -// Deletes a blob container in a storage account. -// Parameters: -// resourceGroupName - name of the resource group within the azure subscription. -// accountName - the name of the storage account -// containerName - the name of the container -func (manager *mockBlobContainerManager) DeleteBlobContainer(ctx context.Context, resourceGroupName string, accountName string, containerName string) (autorest.Response, error) { - containers := manager.blobContainerResource - - index, _ := findBlobContainer(containers, func(g blobContainerResource) bool { - return g.resourceGroupName == resourceGroupName && - g.storageAccountName == accountName && - g.blobContainerName == containerName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("blob container not found") - } - - manager.blobContainerResource = append(containers[:index], containers[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} diff --git a/pkg/resourcemanager/mock/storages/filesystem.go b/pkg/resourcemanager/mock/storages/filesystem.go deleted file mode 100644 index 45f3c0d566f..00000000000 --- a/pkg/resourcemanager/mock/storages/filesystem.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package storages - -import ( - "context" - "errors" - "github.com/Azure/azure-service-operator/pkg/errhelp" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "net/http" -) - -type fileSystemResource struct { - resourceGroupName string - storageAccountName string - filesystemName string -} - -type mockFileSystemManager struct { - fileSystemResource []fileSystemResource -} - -func findFileSystem(res []fileSystemResource, predicate func(fileSystemResource) bool) (int, fileSystemResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, fileSystemResource{} -} - -// Creates a filesystem in a storage account -func (manager *mockFileSystemManager) CreateFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (*autorest.Response, error) { - fs := fileSystemResource{ - resourceGroupName: groupName, - storageAccountName: datalakeName, - filesystemName: filesystemName, - } - - manager.fileSystemResource = append(manager.fileSystemResource, fs) - mockresponse := helpers.GetRestResponse(http.StatusOK) - - return &mockresponse, nil -} - -// Gets a filesystem -func (manager *mockFileSystemManager) GetFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (autorest.Response, error) { - groups := manager.fileSystemResource - - index, _ := findFileSystem(groups, func(g fileSystemResource) bool { - return g.resourceGroupName == groupName && - g.storageAccountName == datalakeName && - g.filesystemName == filesystemName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errhelp.NewAzureError(errors.New("filesystem not found")) - } - return helpers.GetRestResponse(http.StatusOK), nil -} - -// Deletes the filesystem -func (manager *mockFileSystemManager) DeleteFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (autorest.Response, error) { - groups := manager.fileSystemResource - - index, _ := findFileSystem(groups, func(g fileSystemResource) bool { - return g.resourceGroupName == groupName && - g.storageAccountName == datalakeName && - g.filesystemName == filesystemName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errhelp.NewAzureError(errors.New("filesystem not found")) - } - - manager.fileSystemResource = append(groups[:index], groups[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} diff --git a/pkg/resourcemanager/mock/storages/storageaccount.go b/pkg/resourcemanager/mock/storages/storageaccount.go deleted file mode 100644 index 48a939f73a4..00000000000 --- a/pkg/resourcemanager/mock/storages/storageaccount.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package storages - -import ( - "context" - "errors" - "net/http" - - storage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" - azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/mock/helpers" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/to" -) - -type storageResource struct { - resourceGroupName string - storageAccountName string - StorageAccount storage.Account -} - -type mockStorageManager struct { - storageResource []storageResource -} - -func findStorage(res []storageResource, predicate func(storageResource) bool) (int, storageResource) { - for index, r := range res { - if predicate(r) { - return index, r - } - } - return -1, storageResource{} -} - -type Finder interface { -} - -type StorageResources []storageResource - -func (srs *StorageResources) Find(predicate func(storageResource) bool) { - -} - -func (manager *mockStorageManager) CreateStorage(ctx context.Context, groupName string, - storageAccountName string, - location string, - sku azurev1alpha1.StorageAccountSku, - kind azurev1alpha1.StorageAccountKind, - tags map[string]*string, - accessTier azurev1alpha1.StorageAccountAccessTier, - enableHTTPsTrafficOnly *bool, dataLakeEnabled *bool, networkRule *azurev1alpha1.NetworkRuleSet) (result storage.Account, err error) { - s := storageResource{ - resourceGroupName: groupName, - storageAccountName: storageAccountName, - StorageAccount: storage.Account{ - Response: helpers.GetRestResponse(201), - Tags: tags, - Location: to.StringPtr(location), - Name: to.StringPtr(storageAccountName), - AccountProperties: &storage.AccountProperties{ - ProvisioningState: storage.Succeeded, - }, - }, - } - - manager.storageResource = append(manager.storageResource, s) - return s.StorageAccount, nil -} - -// Get gets the description of the specified storage account. -func (manager *mockStorageManager) GetStorage(ctx context.Context, resourceGroupName string, storageAccountName string) (storage.Account, error) { - groups := manager.storageResource - - index, group := findStorage(groups, func(g storageResource) bool { - return g.resourceGroupName == resourceGroupName && - g.storageAccountName == storageAccountName - }) - - if index == -1 { - return storage.Account{}, errors.New("storage account not found") - } - - return group.StorageAccount, nil -} - -// removes the storage account -func (manager *mockStorageManager) DeleteStorage(ctx context.Context, resourceGroupName string, storageAccountName string) (autorest.Response, error) { - groups := manager.storageResource - - index, _ := findStorage(groups, func(g storageResource) bool { - return g.resourceGroupName == resourceGroupName && - g.storageAccountName == storageAccountName - }) - - if index == -1 { - return helpers.GetRestResponse(http.StatusNotFound), errors.New("storage account not found") - } - - manager.storageResource = append(groups[:index], groups[index+1:]...) - - return helpers.GetRestResponse(http.StatusOK), nil -} diff --git a/pkg/resourcemanager/mysql/vnetrule/reconcile.go b/pkg/resourcemanager/mysql/vnetrule/reconcile.go index e49c0f8dc97..6f38cf4d4fc 100644 --- a/pkg/resourcemanager/mysql/vnetrule/reconcile.go +++ b/pkg/resourcemanager/mysql/vnetrule/reconcile.go @@ -66,6 +66,9 @@ func (vr *MySQLVNetRuleClient) Ensure(ctx context.Context, obj runtime.Object, o return false, nil } + fatalErr := []string{ + errhelp.VirtualNetworkRuleBadRequest, + } ignorableErrors := []string{ errhelp.ResourceGroupNotFoundErrorCode, errhelp.ParentNotFoundErrorCode, @@ -76,6 +79,14 @@ func (vr *MySQLVNetRuleClient) Ensure(ctx context.Context, obj runtime.Object, o return false, nil } + if helpers.ContainsString(fatalErr, azerr.Type) { + instance.Status.Message = azerr.Error() + instance.Status.Provisioning = false + instance.Status.Provisioned = false + instance.Status.FailedProvisioning = true + return true, nil + } + // this happens when we try to create the VNet rule and the server doesnt exist yet errorString := err.Error() if strings.Contains(errorString, "does not have the server") { diff --git a/pkg/resourcemanager/psql/vnetrule/client.go b/pkg/resourcemanager/psql/vnetrule/client.go new file mode 100644 index 00000000000..466af00bcd6 --- /dev/null +++ b/pkg/resourcemanager/psql/vnetrule/client.go @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package server + +import ( + "context" + + network "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network" + psql "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" + "github.com/Azure/azure-service-operator/pkg/resourcemanager/config" + "github.com/Azure/azure-service-operator/pkg/resourcemanager/iam" +) + +type PostgreSQLVNetRuleClient struct { +} + +func NewPostgreSQLVNetRuleClient() *PostgreSQLVNetRuleClient { + return &PostgreSQLVNetRuleClient{} +} + +func GetPostgreSQLVNetRulesClient() psql.VirtualNetworkRulesClient { + VNetRulesClient := psql.NewVirtualNetworkRulesClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + VNetRulesClient.Authorizer = a + VNetRulesClient.AddToUserAgent(config.UserAgent()) + return VNetRulesClient +} + +// retrieves the Subnetclient +func GetGoNetworkSubnetClient() network.SubnetsClient { + SubnetsClient := network.NewSubnetsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) + a, _ := iam.GetResourceManagementAuthorizer() + SubnetsClient.Authorizer = a + SubnetsClient.AddToUserAgent(config.UserAgent()) + return SubnetsClient +} + +// GetPostgreSQLVNetRule returns a VNet rule +func (vr *PostgreSQLVNetRuleClient) GetPostgreSQLVNetRule( + ctx context.Context, + resourceGroupName string, + serverName string, + ruleName string) (result psql.VirtualNetworkRule, err error) { + + VNetRulesClient := GetPostgreSQLVNetRulesClient() + + return VNetRulesClient.Get( + ctx, + resourceGroupName, + serverName, + ruleName, + ) +} + +// deletes a VNet rule +func (vr *PostgreSQLVNetRuleClient) DeletePostgreSQLVNetRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (err error) { + + // check to see if the rule exists, if it doesn't then short-circuit + _, err = vr.GetPostgreSQLVNetRule(ctx, resourceGroupName, serverName, ruleName) + if err != nil { + return nil + } + + VNetRulesClient := GetPostgreSQLVNetRulesClient() + _, err = VNetRulesClient.Delete( + ctx, + resourceGroupName, + serverName, + ruleName, + ) + + return err +} + +// creates or updates a VNet rule +func (vr *PostgreSQLVNetRuleClient) CreateOrUpdatePostgreSQLVNetRule( + ctx context.Context, + resourceGroupName string, + serverName string, + ruleName string, + VNetRG string, + VNetName string, + SubnetName string, + IgnoreServiceEndpoint bool) (vnr psql.VirtualNetworkRule, err error) { + + VNetRulesClient := GetPostgreSQLVNetRulesClient() + SubnetClient := GetGoNetworkSubnetClient() + + // Get ARM Resource ID of Subnet based on the VNET name, Subnet name and Subnet Address Prefix + subnet, err := SubnetClient.Get(ctx, VNetRG, VNetName, SubnetName, "") + if err != nil { + return vnr, err + } + subnetResourceID := *subnet.ID + + // Populate parameters with the right ID + parameters := psql.VirtualNetworkRule{ + VirtualNetworkRuleProperties: &psql.VirtualNetworkRuleProperties{ + VirtualNetworkSubnetID: &subnetResourceID, + IgnoreMissingVnetServiceEndpoint: &IgnoreServiceEndpoint, + }, + } + + // Call CreateOrUpdate + result, err := VNetRulesClient.CreateOrUpdate( + ctx, + resourceGroupName, + serverName, + ruleName, + parameters, + ) + return result.Result(VNetRulesClient) +} diff --git a/pkg/resourcemanager/psql/vnetrule/manager.go b/pkg/resourcemanager/psql/vnetrule/manager.go new file mode 100644 index 00000000000..8032c17588d --- /dev/null +++ b/pkg/resourcemanager/psql/vnetrule/manager.go @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package server + +import ( + "context" + + psql "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" + "github.com/Azure/azure-service-operator/pkg/resourcemanager" +) + +type PostgreSqlVNetRuleManager interface { + CreateOrUpdatePostgreSQLVNetRule( + ctx context.Context, + resourceGroupName string, + serverName string, + ruleName string, + VNetRG string, + VNetName string, + SubnetName string, + IgnoreServiceEndpoint bool) (result psql.VirtualNetworkRule, err error) + DeletePostgreSQLVNetRule(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (err error) + GetPostgreSQLVNetRulesClient(ctx context.Context, resourceGroupName string, serverName string, ruleName string) (result psql.VirtualNetworkRule, err error) + resourcemanager.ARMClient +} diff --git a/pkg/resourcemanager/psql/vnetrule/reconcile.go b/pkg/resourcemanager/psql/vnetrule/reconcile.go new file mode 100644 index 00000000000..57c1673b805 --- /dev/null +++ b/pkg/resourcemanager/psql/vnetrule/reconcile.go @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package server + +import ( + "context" + "fmt" + "strings" + + psql "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" + + azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" + "github.com/Azure/azure-service-operator/pkg/errhelp" + "github.com/Azure/azure-service-operator/pkg/helpers" + "github.com/Azure/azure-service-operator/pkg/resourcemanager" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" +) + +// Ensure creates a postgresqlvnetrule +func (vr *PostgreSQLVNetRuleClient) Ensure(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { + instance, err := vr.convert(obj) + if err != nil { + return false, err + } + + groupName := instance.Spec.ResourceGroup + server := instance.Spec.Server + ruleName := instance.ObjectMeta.Name + virtualNetworkRG := instance.Spec.VNetResourceGroup + virtualnetworkname := instance.Spec.VNetName + subnetName := instance.Spec.SubnetName + ignoreendpoint := instance.Spec.IgnoreMissingServiceEndpoint + + vnetrule, err := vr.GetPostgreSQLVNetRule(ctx, groupName, server, ruleName) + if err == nil { + if vnetrule.VirtualNetworkRuleProperties != nil && vnetrule.VirtualNetworkRuleProperties.State == psql.Ready { + instance.Status.Provisioning = false + instance.Status.Provisioned = true + instance.Status.Message = resourcemanager.SuccessMsg + instance.Status.ResourceId = *vnetrule.ID + return true, nil + } + return false, nil + } + instance.Status.Message = fmt.Sprintf("PostgreSQLVNetRule Get error %s", err.Error()) + requeuErrors := []string{ + errhelp.ResourceGroupNotFoundErrorCode, + errhelp.ParentNotFoundErrorCode, + } + azerr := errhelp.NewAzureErrorAzureError(err) + if helpers.ContainsString(requeuErrors, azerr.Type) { + instance.Status.Provisioning = false + return false, nil + } + + instance.Status.Provisioning = true + _, err = vr.CreateOrUpdatePostgreSQLVNetRule(ctx, groupName, server, ruleName, virtualNetworkRG, virtualnetworkname, subnetName, ignoreendpoint) + if err != nil { + instance.Status.Message = err.Error() + azerr := errhelp.NewAzureErrorAzureError(err) + + if azerr.Type == errhelp.AsyncOpIncompleteError { + instance.Status.Provisioning = true + instance.Status.Message = "Resource request submitted to Azure successfully" + return false, nil + } + + fatalErr := []string{ + errhelp.VirtualNetworkRuleBadRequest, + } + ignorableErrors := []string{ + errhelp.ResourceGroupNotFoundErrorCode, + errhelp.ParentNotFoundErrorCode, + errhelp.ResourceNotFound, + errhelp.FeatureNotSupportedForEdition, + } + if helpers.ContainsString(ignorableErrors, azerr.Type) { + instance.Status.Provisioning = false + return false, nil + } + if helpers.ContainsString(fatalErr, azerr.Type) { + instance.Status.Message = azerr.Error() + instance.Status.Provisioning = false + instance.Status.Provisioned = false + instance.Status.FailedProvisioning = true + return true, nil + } + + // this happens when we try to create the VNet rule and the server doesnt exist yet + errorString := err.Error() + if strings.Contains(errorString, "does not have the server") { + instance.Status.Provisioning = false + return false, nil + } + + return false, err + } + + return false, nil // We requeue so the success can be caught in the Get() path +} + +// Delete Vnetrules +func (vr *PostgreSQLVNetRuleClient) Delete(ctx context.Context, obj runtime.Object, opts ...resourcemanager.ConfigOption) (bool, error) { + instance, err := vr.convert(obj) + if err != nil { + return false, err + } + + groupName := instance.Spec.ResourceGroup + server := instance.Spec.Server + ruleName := instance.ObjectMeta.Name + + err = vr.DeletePostgreSQLVNetRule(ctx, groupName, server, ruleName) + if err != nil { + instance.Status.Message = err.Error() + + azerr := errhelp.NewAzureErrorAzureError(err) + // these errors are expected + ignore := []string{ + errhelp.AsyncOpIncompleteError, + } + + // this means the thing doesn't exist + finished := []string{ + errhelp.ResourceNotFound, + errhelp.ParentNotFoundErrorCode, + } + + if helpers.ContainsString(ignore, azerr.Type) { + return true, nil //requeue + } + + if helpers.ContainsString(finished, azerr.Type) { + return false, nil //end reconcile + } + return false, err + } + + return false, nil +} + +// GetParents returns the parent of postgresqlvnetrule +func (vr *PostgreSQLVNetRuleClient) GetParents(obj runtime.Object) ([]resourcemanager.KubeParent, error) { + instance, err := vr.convert(obj) + if err != nil { + return nil, err + } + + return []resourcemanager.KubeParent{ + { + Key: types.NamespacedName{ + Namespace: instance.Namespace, + Name: instance.Spec.Server, + }, + Target: &azurev1alpha1.PostgreSQLServer{}, + }, + { + Key: types.NamespacedName{ + Namespace: instance.Namespace, + Name: instance.Spec.ResourceGroup, + }, + Target: &azurev1alpha1.ResourceGroup{}, + }, + }, nil +} + +func (vr *PostgreSQLVNetRuleClient) GetStatus(obj runtime.Object) (*azurev1alpha1.ASOStatus, error) { + instance, err := vr.convert(obj) + if err != nil { + return nil, err + } + return &instance.Status, nil +} + +func (vr *PostgreSQLVNetRuleClient) convert(obj runtime.Object) (*azurev1alpha1.PostgreSQLVNetRule, error) { + local, ok := obj.(*azurev1alpha1.PostgreSQLVNetRule) + if !ok { + return nil, fmt.Errorf("failed type assertion on kind: %s", obj.GetObjectKind().GroupVersionKind().String()) + } + return local, nil +} diff --git a/pkg/resourcemanager/resourcegroups/resourcegroup.go b/pkg/resourcemanager/resourcegroups/resourcegroup.go index 269e1f55a20..20f49aa12de 100644 --- a/pkg/resourcemanager/resourcegroups/resourcegroup.go +++ b/pkg/resourcemanager/resourcegroups/resourcegroup.go @@ -5,6 +5,7 @@ package resourcegroups import ( "context" + "net/http" "strings" "sync" @@ -20,33 +21,36 @@ import ( // AzureResourceGroupManager is the struct which contains helper functions for resource groups type AzureResourceGroupManager struct{} -func getGroupsClient() resources.GroupsClient { +func getGroupsClient() (resources.GroupsClient, error) { groupsClient := resources.NewGroupsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) a, err := iam.GetResourceManagementAuthorizer() if err != nil { - return resources.GroupsClient{} + return resources.GroupsClient{}, err } groupsClient.Authorizer = a groupsClient.AddToUserAgent(config.UserAgent()) - return groupsClient + return groupsClient, nil } -func getGroupsClientWithAuthFile() resources.GroupsClient { +func getGroupsClientWithAuthFile() (resources.GroupsClient, error) { groupsClient := resources.NewGroupsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) // requires env var AZURE_AUTH_LOCATION set to output of // `az ad sp create-for-rbac --sdk-auth` a, err := auth.NewAuthorizerFromFile(config.BaseURI()) if err != nil { - return resources.GroupsClient{} + return resources.GroupsClient{}, err } groupsClient.Authorizer = a groupsClient.AddToUserAgent(config.UserAgent()) - return groupsClient + return groupsClient, nil } // CreateGroup creates a new resource group named by env var func (_ *AzureResourceGroupManager) CreateGroup(ctx context.Context, groupName string, location string) (resources.Group, error) { - groupsClient := getGroupsClient() + groupsClient, err := getGroupsClient() + if err != nil { + return resources.Group{}, err + } return groupsClient.CreateOrUpdate( ctx, @@ -59,7 +63,11 @@ func (_ *AzureResourceGroupManager) CreateGroup(ctx context.Context, groupName s // CreateGroupWithAuthFile creates a new resource group. The client authorizer // is set up based on an auth file created using the Azure CLI. func CreateGroupWithAuthFile(ctx context.Context, groupName string, location string) (resources.Group, error) { - groupsClient := getGroupsClientWithAuthFile() + groupsClient, err := getGroupsClientWithAuthFile() + if err != nil { + return resources.Group{}, err + } + return groupsClient.CreateOrUpdate( ctx, groupName, @@ -70,7 +78,14 @@ func CreateGroupWithAuthFile(ctx context.Context, groupName string, location str // DeleteGroup removes the resource group named by env var func (_ *AzureResourceGroupManager) DeleteGroup(ctx context.Context, groupName string) (result autorest.Response, err error) { - var client = getGroupsClient() + client, err := getGroupsClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } future, err := client.Delete(ctx, groupName) if err != nil { @@ -85,19 +100,31 @@ func (_ *AzureResourceGroupManager) DeleteGroupAsync(ctx context.Context, groupN } func deleteGroupAsync(ctx context.Context, groupName string) (result resources.GroupsDeleteFuture, err error) { - groupsClient := getGroupsClient() + groupsClient, err := getGroupsClient() + if err != nil { + return resources.GroupsDeleteFuture{}, err + } + return groupsClient.Delete(ctx, groupName) } // ListGroups gets an interator that gets all resource groups in the subscription func ListGroups(ctx context.Context) (resources.GroupListResultIterator, error) { - groupsClient := getGroupsClient() + groupsClient, err := getGroupsClient() + if err != nil { + return resources.GroupListResultIterator{}, err + } + return groupsClient.ListComplete(ctx, "", nil) } // GetGroup gets info on the resource group in use func GetGroup(ctx context.Context, groupName string) (resources.Group, error) { - groupsClient := getGroupsClient() + groupsClient, err := getGroupsClient() + if err != nil { + return resources.Group{}, err + } + return groupsClient.Get(ctx, groupName) } @@ -126,7 +153,12 @@ func WaitForDeleteCompletion(ctx context.Context, wg *sync.WaitGroup, futures [] for i, f := range futures { wg.Add(1) go func(ctx context.Context, future resources.GroupsDeleteFuture, rg string) { - err := future.WaitForCompletionRef(ctx, getGroupsClient().Client) + client, err := getGroupsClient() + if err != nil { + return + } + + err = future.WaitForCompletionRef(ctx, client.Client) if err != nil { return } @@ -137,7 +169,15 @@ func WaitForDeleteCompletion(ctx context.Context, wg *sync.WaitGroup, futures [] // CheckExistence checks whether a resource exists func (_ *AzureResourceGroupManager) CheckExistence(ctx context.Context, resourceGroupName string) (result autorest.Response, err error) { - groupsClient := getGroupsClient() + groupsClient, err := getGroupsClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + result, _ = groupsClient.CheckExistence(ctx, resourceGroupName) return } diff --git a/pkg/resourcemanager/storages/blobcontainer/blob_container.go b/pkg/resourcemanager/storages/blobcontainer/blob_container.go index 2096fcb3404..2ce94406822 100644 --- a/pkg/resourcemanager/storages/blobcontainer/blob_container.go +++ b/pkg/resourcemanager/storages/blobcontainer/blob_container.go @@ -5,6 +5,7 @@ package blobcontainer import ( "context" + "net/http" s "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" "github.com/Azure/azure-service-operator/pkg/resourcemanager/config" @@ -14,12 +15,15 @@ import ( type AzureBlobContainerManager struct{} -func getContainerClient() s.BlobContainersClient { +func getContainerClient() (s.BlobContainersClient, error) { containersClient := s.NewBlobContainersClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - auth, _ := iam.GetResourceManagementAuthorizer() + auth, err := iam.GetResourceManagementAuthorizer() + if err != nil { + return s.BlobContainersClient{}, err + } containersClient.Authorizer = auth containersClient.AddToUserAgent(config.UserAgent()) - return containersClient + return containersClient, nil } // Creates a blob container in a storage account. @@ -29,7 +33,10 @@ func getContainerClient() s.BlobContainersClient { // containerName - the name of the container // accessLevel - 'PublicAccessContainer', 'PublicAccessBlob', or 'PublicAccessNone' func (bc *AzureBlobContainerManager) CreateBlobContainer(ctx context.Context, resourceGroupName string, accountName string, containerName string, accessLevel s.PublicAccess) (*s.BlobContainer, error) { - containerClient := getContainerClient() + containerClient, err := getContainerClient() + if err != nil { + return nil, err + } blobContainerProperties := s.ContainerProperties{ PublicAccess: accessLevel, @@ -55,7 +62,11 @@ func (bc *AzureBlobContainerManager) CreateBlobContainer(ctx context.Context, re // accountName - the name of the storage account // containerName - the name of the container func (bc *AzureBlobContainerManager) GetBlobContainer(ctx context.Context, resourceGroupName string, accountName string, containerName string) (result s.BlobContainer, err error) { - containerClient := getContainerClient() + containerClient, err := getContainerClient() + if err != nil { + return s.BlobContainer{}, err + } + return containerClient.Get(ctx, resourceGroupName, accountName, containerName) } @@ -65,7 +76,15 @@ func (bc *AzureBlobContainerManager) GetBlobContainer(ctx context.Context, resou // accountName - the name of the storage account // containerName - the name of the container func (bc *AzureBlobContainerManager) DeleteBlobContainer(ctx context.Context, resourceGroupName string, accountName string, containerName string) (result autorest.Response, err error) { - containerClient := getContainerClient() + containerClient, err := getContainerClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + return containerClient.Delete(ctx, resourceGroupName, accountName, diff --git a/pkg/resourcemanager/storages/filesystem.go b/pkg/resourcemanager/storages/filesystem.go deleted file mode 100644 index b9f40c52251..00000000000 --- a/pkg/resourcemanager/storages/filesystem.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package storages - -import ( - "context" - "errors" - "log" - "net/http" - - "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" - "github.com/Azure/azure-sdk-for-go/services/storage/datalake/2019-10-31/storagedatalake" - "github.com/Azure/azure-service-operator/pkg/errhelp" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/config" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/iam" - "github.com/Azure/azure-service-operator/pkg/resourcemanager/storages/storageaccount" - "github.com/Azure/go-autorest/autorest" -) - -type azureFileSystemManager struct{} - -func (_ *azureFileSystemManager) CreateFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (*autorest.Response, error) { - err := checkRGAndStorageAccount(ctx, groupName, datalakeName) - if err != nil { - return nil, err - } - client := getFileSystemClient(ctx, groupName, datalakeName) - // empty parameters are optional request headers (properties, requestid) - result, err := client.Create(ctx, filesystemName, "", "", timeout, xMsDate) - if err != nil { - return nil, err - } - - return &result, err -} - -func (_ *azureFileSystemManager) GetFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (autorest.Response, error) { - response := autorest.Response{Response: &http.Response{StatusCode: http.StatusNotFound}} - - err := checkRGAndStorageAccount(ctx, groupName, datalakeName) - if err != nil { - return response, errors.New("unable to create filesystem") - } - response = autorest.Response{Response: &http.Response{StatusCode: http.StatusNotFound}} - client := getFileSystemClient(ctx, groupName, datalakeName) - - // empty parameters are optional request headers (continuation, maxresults, requestid) - list, err := client.List(ctx, filesystemName, "", nil, "", timeout, xMsDate) - - if len(*list.Filesystems) == 0 { - return response, err - } - - response = list.Response - - return response, err -} - -func (_ *azureFileSystemManager) DeleteFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (autorest.Response, error) { - response := autorest.Response{Response: &http.Response{StatusCode: http.StatusAccepted}} - err := checkRGAndStorageAccount(ctx, groupName, datalakeName) - if err != nil { - return response, nil - } - client := getFileSystemClient(ctx, groupName, datalakeName) - // empty parameters are optional request headers (ifmodifiedsince, ifunmodifiedsince, requestid) - return client.Delete(ctx, filesystemName, "", "", "", timeout, xMsDate) -} - -func getFileSystemClient(ctx context.Context, groupName string, accountName string) storagedatalake.FilesystemClient { - xmsversion := "2019-02-02" - fsClient := storagedatalake.NewFilesystemClient(xmsversion, accountName) - - accountKey, err := getAccountKey(ctx, groupName, accountName) - if err != nil { - log.Printf("failed to get the account key for the authorizer: %v\n", err) - } - - a, err := iam.GetSharedKeyAuthorizer(accountName, accountKey) - - if err != nil { - log.Printf("failed to initialize authorizer: %v\n", err) - } - fsClient.Authorizer = a - fsClient.AddToUserAgent(config.UserAgent()) - - return fsClient -} - -func getResourcesClient() resources.GroupsClient { - resourcesClient := resources.NewGroupsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) - a, _ := iam.GetResourceManagementAuthorizer() - resourcesClient.Authorizer = a - resourcesClient.AddToUserAgent(config.UserAgent()) - return resourcesClient -} - -func checkRGAndStorageAccount(ctx context.Context, groupName string, datalakeName string) error { - rgClient := getResourcesClient() - storagesClient := storageaccount.New() - - response, err := rgClient.CheckExistence(ctx, groupName) - if response.IsHTTPStatus(404) { - return errhelp.NewAzureError(errors.New("ResourceGroupNotFound")) - } - - _, err = storagesClient.ListKeys(ctx, groupName, datalakeName) - if err != nil { - return errhelp.NewAzureError(errors.New("ParentResourceNotFound")) - } - - return err -} - -func getAccountKey(ctx context.Context, groupName string, accountName string) (accountKey string, err error) { - adlsClient := storageaccount.New() - keys, err := adlsClient.ListKeys(ctx, groupName, accountName) - if err != nil { - return "", err - } - - for _, key := range *keys.Keys { - if *key.KeyName == "key1" { - accountKey = *key.Value - } - } - return accountKey, err -} diff --git a/pkg/resourcemanager/storages/filesystem_manager.go b/pkg/resourcemanager/storages/filesystem_manager.go deleted file mode 100644 index 2a74d851c6b..00000000000 --- a/pkg/resourcemanager/storages/filesystem_manager.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package storages - -import ( - "context" - "github.com/Azure/go-autorest/autorest" -) - -type FileSystemManager interface { - CreateFileSystem(ctx context.Context, goupName string, filesystem string, timeout *int32, xMsDate string, accountName string) (*autorest.Response, error) - - GetFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (autorest.Response, error) - - DeleteFileSystem(ctx context.Context, groupName string, filesystemName string, timeout *int32, xMsDate string, datalakeName string) (autorest.Response, error) -} diff --git a/pkg/resourcemanager/storages/filesystem_test.go b/pkg/resourcemanager/storages/filesystem_test.go deleted file mode 100644 index 586e190c9dd..00000000000 --- a/pkg/resourcemanager/storages/filesystem_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -package storages - -import ( - . "github.com/onsi/ginkgo" -) - -var _ = Describe("File System", func() { - - // const timeout = time.Second * 180 - - // adlsName := "tdevadls" + helpers.RandomString(10) - - // ctx := context.Background() - - // BeforeEach(func() { - // // Add any setup steps that needs to be executed before each test - // // Create a data lake enbaled storage account - // adlsLocation := config.DefaultLocation() - // _, _ = tc.StorageManagers.Storage.CreateStorage(ctx, tc.ResourceGroupName, adlsName, adlsLocation, azurev1alpha1.StorageSku{ - // Name: "Standard_LRS", - // }, "StorageV2", map[string]*string{}, "", nil, to.BoolPtr(true)) - - // Eventually(func() s.ProvisioningState { - // result, _ := tc.StorageManagers.Storage.GetStorage(ctx, tc.ResourceGroupName, adlsName) - // return result.ProvisioningState - // }, tc.timeout, tc.retryInterval, - // ).Should(Equal(s.Succeeded)) - // }) - - // AfterEach(func() { - // // Add any teardown steps that needs to be executed after each test - // _, err := tc.StorageManagers.Storage.DeleteStorage(context.Background(), tc.ResourceGroupName, adlsName) - // Expect(err).NotTo(HaveOccurred()) - // }) - - // Context("Create and Delete File System Instances", func() { - // It("should create and delete filesystems in azure data lake", func() { - - // fileSystemManager := tc.StorageManagers.FileSystem - // fileSystemName := "tfilesystem" + helpers.RandomString(5) - // requestTimeout := to.Int32Ptr(20) - // xMsDate := time.Now().String() - - // var err error - - // _, err = fileSystemManager.CreateFileSystem(context.Background(), tc.ResourceGroupName, fileSystemName, requestTimeout, xMsDate, adlsName) - // Expect(err).NotTo(HaveOccurred()) - - // Eventually(func() bool { - // result, _ := fileSystemManager.GetFileSystem(context.Background(), tc.ResourceGroupName, fileSystemName, requestTimeout, xMsDate, adlsName) - // return result.Response.StatusCode == http.StatusOK - // }, timeout, - // ).Should(BeTrue()) - - // _, err = fileSystemManager.DeleteFileSystem(context.Background(), tc.ResourceGroupName, fileSystemName, requestTimeout, xMsDate, adlsName) - // Expect(err).NotTo(HaveOccurred()) - - // Eventually(func() bool { - // result, _ := fileSystemManager.GetFileSystem(context.Background(), tc.ResourceGroupName, fileSystemName, requestTimeout, xMsDate, adlsName) - // return result.Response.StatusCode == http.StatusNotFound - // }, timeout, - // ).Should(BeTrue()) - - // }) - // }) -}) diff --git a/pkg/resourcemanager/storages/managers.go b/pkg/resourcemanager/storages/managers.go index 3fdd5a6f62e..ef150cac9df 100644 --- a/pkg/resourcemanager/storages/managers.go +++ b/pkg/resourcemanager/storages/managers.go @@ -11,11 +11,9 @@ import ( type StorageManagers struct { StorageAccount storageaccount.StorageManager BlobContainer blobcontainer.BlobContainerManager - FileSystem FileSystemManager } var AzureStorageManagers = StorageManagers{ StorageAccount: storageaccount.New(), BlobContainer: blobcontainer.New(), - FileSystem: &azureFileSystemManager{}, } diff --git a/pkg/resourcemanager/storages/storageaccount/storageaccount.go b/pkg/resourcemanager/storages/storageaccount/storageaccount.go index e2e75b353d6..e6421b32320 100644 --- a/pkg/resourcemanager/storages/storageaccount/storageaccount.go +++ b/pkg/resourcemanager/storages/storageaccount/storageaccount.go @@ -6,7 +6,7 @@ package storageaccount import ( "context" "errors" - "log" + "net/http" "strings" "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" @@ -70,15 +70,15 @@ func ParseNetworkPolicy(ruleSet *v1alpha1.StorageNetworkRuleSet) storage.Network } } -func getStoragesClient() storage.AccountsClient { +func getStoragesClient() (storage.AccountsClient, error) { storagesClient := storage.NewAccountsClientWithBaseURI(config.BaseURI(), config.SubscriptionID()) a, err := iam.GetResourceManagementAuthorizer() if err != nil { - log.Printf("failed to initialize authorizer: %v\n", err) + return storage.AccountsClient{}, err } storagesClient.Authorizer = a storagesClient.AddToUserAgent(config.UserAgent()) - return storagesClient + return storagesClient, nil } // CreateStorage creates a new storage account @@ -92,7 +92,10 @@ func (_ *azureStorageManager) CreateStorage(ctx context.Context, accessTier azurev1alpha1.StorageAccountAccessTier, enableHTTPsTrafficOnly *bool, dataLakeEnabled *bool, networkRule *storage.NetworkRuleSet) (pollingURL string, result storage.Account, err error) { - storagesClient := getStoragesClient() + storagesClient, err := getStoragesClient() + if err != nil { + return "", storage.Account{}, err + } //Check if name is available storageType := "Microsoft.Storage/storageAccounts" @@ -150,17 +153,33 @@ func (_ *azureStorageManager) CreateStorage(ctx context.Context, // resourceGroupName - name of the resource group within the azure subscription. // storageAccountName - the name of the storage account func (_ *azureStorageManager) GetStorage(ctx context.Context, resourceGroupName string, storageAccountName string) (result storage.Account, err error) { - storagesClient := getStoragesClient() + storagesClient, err := getStoragesClient() + if err != nil { + return storage.Account{}, err + } + return storagesClient.GetProperties(ctx, resourceGroupName, storageAccountName, "") } // DeleteStorage removes the resource group named by env var func (_ *azureStorageManager) DeleteStorage(ctx context.Context, groupName string, storageAccountName string) (result autorest.Response, err error) { - storagesClient := getStoragesClient() + storagesClient, err := getStoragesClient() + if err != nil { + return autorest.Response{ + Response: &http.Response{ + StatusCode: 500, + }, + }, err + } + return storagesClient.Delete(ctx, groupName, storageAccountName) } func (_ *azureStorageManager) ListKeys(ctx context.Context, resourceGroupName string, accountName string) (result storage.AccountListKeysResult, err error) { - storagesClient := getStoragesClient() + storagesClient, err := getStoragesClient() + if err != nil { + return storage.AccountListKeysResult{}, err + } + return storagesClient.ListKeys(ctx, resourceGroupName, accountName, storage.Kerb) } diff --git a/pkg/resourcemanager/vnet/reconcile.go b/pkg/resourcemanager/vnet/reconcile.go index 931147dbfd7..d1d9c3bd255 100644 --- a/pkg/resourcemanager/vnet/reconcile.go +++ b/pkg/resourcemanager/vnet/reconcile.go @@ -6,6 +6,8 @@ package vnet import ( "context" "fmt" + "net/http" + "strings" azurev1alpha1 "github.com/Azure/azure-service-operator/api/v1alpha1" "github.com/Azure/azure-service-operator/pkg/errhelp" @@ -36,15 +38,14 @@ func (g *AzureVNetManager) Ensure(ctx context.Context, obj runtime.Object, opts // succeeded! end reconcilliation successfully instance.Status.Provisioning = false instance.Status.Provisioned = true + instance.Status.FailedProvisioning = false instance.Status.Message = resourcemanager.SuccessMsg instance.Status.ResourceId = *vNet.ID return true, nil } instance.Status.Provisioning = true - instance.Status.Provisioned = false - - _, err = g.CreateVNet( + result, err := g.CreateVNet( ctx, location, resourceGroup, @@ -54,11 +55,17 @@ func (g *AzureVNetManager) Ensure(ctx context.Context, obj runtime.Object, opts ) if err != nil { azerr := errhelp.NewAzureErrorAzureError(err) + instance.Status.Message = err.Error() + + if result.Response.Response != nil && result.Response.Response.StatusCode == http.StatusBadRequest { + instance.Status.Provisioning = false + return true, nil + } + catch := []string{ errhelp.ResourceGroupNotFoundErrorCode, errhelp.ParentNotFoundErrorCode, errhelp.NotFoundErrorCode, - errhelp.AsyncOpIncompleteError, } catchUnrecoverableErrors := []string{ errhelp.NetcfgInvalidIPAddressPrefix, @@ -66,24 +73,31 @@ func (g *AzureVNetManager) Ensure(ctx context.Context, obj runtime.Object, opts errhelp.NetcfgInvalidVirtualNetworkSite, errhelp.InvalidCIDRNotation, errhelp.InvalidRequestFormat, + errhelp.LocationNotAvailableForResourceType, + errhelp.InvalidAddressPrefixFormat, } - if helpers.ContainsString(catch, azerr.Type) { - switch azerr.Type { - case errhelp.AsyncOpIncompleteError: - instance.Status.Provisioning = true - } - // reconciliation is not done but error is acceptable + // everything ok - just requeue + if strings.Contains(azerr.Type, errhelp.AsyncOpIncompleteError) { return false, nil } - if helpers.ContainsString(catchUnrecoverableErrors, azerr.Type) { - // Unrecoverable error, so stop reconcilation + // reconciliation is not done but error is acceptable + if helpers.ContainsString(catch, azerr.Type) { instance.Status.Provisioning = false - instance.Status.Message = "Reconcilation hit unrecoverable error" - return true, nil + return false, nil + } + instance.Status.Provisioning = false + + // Unrecoverable error, so stop reconcilation + if helpers.ContainsString(catchUnrecoverableErrors, azerr.Type) { + instance.Status.FailedProvisioning = true + instance.Status.Message = fmt.Sprintf("Reconcilation hit unrecoverable error: %s", errhelp.StripErrorIDs(err)) + return true, nil + } + return false, fmt.Errorf("Error creating VNet: %s, %s - %v", resourceGroup, resourceName, err) } diff --git a/pkg/resourcemanager/vnet/vnet.go b/pkg/resourcemanager/vnet/vnet.go index 00e43f907d4..2116c240f27 100644 --- a/pkg/resourcemanager/vnet/vnet.go +++ b/pkg/resourcemanager/vnet/vnet.go @@ -12,6 +12,7 @@ import ( "github.com/Azure/azure-service-operator/pkg/resourcemanager/iam" telemetry "github.com/Azure/azure-service-operator/pkg/telemetry" "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" ) // AzureVNetManager is the struct that the manager functions hang off @@ -33,7 +34,7 @@ func getVNetClient() (vnetwork.VirtualNetworksClient, error) { } // CreateVNet creates VNets -func (_ *AzureVNetManager) CreateVNet(ctx context.Context, location string, resourceGroupName string, resourceName string, addressSpace string, subnets []azurev1alpha1.VNetSubnets) (vnetwork.VirtualNetwork, error) { +func (*AzureVNetManager) CreateVNet(ctx context.Context, location string, resourceGroupName string, resourceName string, addressSpace string, subnets []azurev1alpha1.VNetSubnets) (vnetwork.VirtualNetwork, error) { client, err := getVNetClient() if err != nil { return vnetwork.VirtualNetwork{}, err @@ -41,15 +42,22 @@ func (_ *AzureVNetManager) CreateVNet(ctx context.Context, location string, reso var subnetsToAdd []vnetwork.Subnet for i := 0; i < len(subnets); i++ { - subnetsToAdd = append( - subnetsToAdd, - vnetwork.Subnet{ - Name: &subnets[i].SubnetName, - SubnetPropertiesFormat: &vnetwork.SubnetPropertiesFormat{ - AddressPrefix: &subnets[i].SubnetAddressPrefix, - }, + eps := []vnetwork.ServiceEndpointPropertiesFormat{} + for _, ep := range subnets[i].ServiceEndpoints { + eps = append(eps, vnetwork.ServiceEndpointPropertiesFormat{ + Service: to.StringPtr(ep), + }) + } + + s := vnetwork.Subnet{ + Name: &subnets[i].SubnetName, + SubnetPropertiesFormat: &vnetwork.SubnetPropertiesFormat{ + AddressPrefix: &subnets[i].SubnetAddressPrefix, + ServiceEndpoints: &eps, }, - ) + } + + subnetsToAdd = append(subnetsToAdd, s) } future, err := client.CreateOrUpdate( @@ -67,14 +75,16 @@ func (_ *AzureVNetManager) CreateVNet(ctx context.Context, location string, reso }, ) if err != nil { - return vnetwork.VirtualNetwork{}, err + return vnetwork.VirtualNetwork{ + Response: autorest.Response{Response: future.Response()}, + }, err } return future.Result(client) } // DeleteVNet deletes a VNet -func (_ *AzureVNetManager) DeleteVNet(ctx context.Context, resourceGroupName string, resourceName string) (autorest.Response, error) { +func (*AzureVNetManager) DeleteVNet(ctx context.Context, resourceGroupName string, resourceName string) (autorest.Response, error) { client, err := getVNetClient() if err != nil { return autorest.Response{}, err