From 6eee36bd9d8c97a545770662258c5f70ebb64c72 Mon Sep 17 00:00:00 2001 From: Erin Corson Date: Tue, 8 Oct 2019 11:08:04 -0600 Subject: [PATCH] Revert "Roll admin credentials for SQL Server" --- PROJECT | 3 - api/v1/sqlaction_types.go | 70 --- api/v1/sqlserver_types.go | 4 - api/v1/zz_generated.deepcopy.go | 89 ---- .../bases/azure.microsoft.com_sqlactions.yaml | 440 ------------------ .../azure.microsoft.com_sqlfirewallrules.yaml | 6 +- config/crd/kustomization.yaml | 3 - .../patches/cainjection_in_sqlactions.yaml | 8 - config/crd/patches/webhook_in_sqlactions.yaml | 17 - config/rbac/role.yaml | 122 ++--- config/samples/azure_v1_sqlaction.yaml | 8 - controllers/sqlaction_controller.go | 227 --------- controllers/sqlserver_controller.go | 120 +---- main.go | 9 - pkg/errhelp/errhelp.go | 5 - .../sqlclient/sqlclient_godsk.go | 21 +- 16 files changed, 84 insertions(+), 1068 deletions(-) delete mode 100644 api/v1/sqlaction_types.go delete mode 100644 config/crd/bases/azure.microsoft.com_sqlactions.yaml delete mode 100644 config/crd/patches/cainjection_in_sqlactions.yaml delete mode 100644 config/crd/patches/webhook_in_sqlactions.yaml delete mode 100644 config/samples/azure_v1_sqlaction.yaml delete mode 100644 controllers/sqlaction_controller.go diff --git a/PROJECT b/PROJECT index b63ba655b48..56e319e160e 100644 --- a/PROJECT +++ b/PROJECT @@ -35,6 +35,3 @@ resources: - group: azure version: v1 kind: ConsumerGroup -- group: azure - version: v1 - kind: SqlAction diff --git a/api/v1/sqlaction_types.go b/api/v1/sqlaction_types.go deleted file mode 100644 index 39321fd9369..00000000000 --- a/api/v1/sqlaction_types.go +++ /dev/null @@ -1,70 +0,0 @@ -/* - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1 - -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. - -// SqlActionSpec defines the desired state of SqlAction -type SqlActionSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - ResourceGroup string `json:"resourcegroup"` - ActionName string `json:"actionname"` - ServerName string `json:"servername"` -} - -// SqlActionStatus defines the observed state of SqlAction -type SqlActionStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - Provisioning bool `json:"provisioning,omitempty"` - Provisioned bool `json:"provisioned,omitempty"` - Message string `json:"state,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status - -// SqlAction is the Schema for the sqlactions API -type SqlAction struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec SqlActionSpec `json:"spec,omitempty"` - Status SqlActionStatus `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// SqlActionList contains a list of SqlAction -type SqlActionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []SqlAction `json:"items"` -} - -func init() { - SchemeBuilder.Register(&SqlAction{}, &SqlActionList{}) -} - -func (s *SqlAction) IsSubmitted() bool { - return s.Status.Provisioned || s.Status.Provisioning -} diff --git a/api/v1/sqlserver_types.go b/api/v1/sqlserver_types.go index 8b76f82e796..23dd415cea3 100644 --- a/api/v1/sqlserver_types.go +++ b/api/v1/sqlserver_types.go @@ -66,7 +66,3 @@ func init() { func (s *SqlServer) IsSubmitted() bool { return s.Status.Provisioned || s.Status.Provisioning } - -func (s *SqlServer) IsProvisioned() bool { - return s.Status.Provisioned -} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 5ea2308cf52..203e7b8e13b 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -887,95 +887,6 @@ func (in *ResourceGroupStatus) DeepCopy() *ResourceGroupStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SqlAction) DeepCopyInto(out *SqlAction) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SqlAction. -func (in *SqlAction) DeepCopy() *SqlAction { - if in == nil { - return nil - } - out := new(SqlAction) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SqlAction) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SqlActionList) DeepCopyInto(out *SqlActionList) { - *out = *in - out.TypeMeta = in.TypeMeta - out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]SqlAction, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SqlActionList. -func (in *SqlActionList) DeepCopy() *SqlActionList { - if in == nil { - return nil - } - out := new(SqlActionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SqlActionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SqlActionSpec) DeepCopyInto(out *SqlActionSpec) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SqlActionSpec. -func (in *SqlActionSpec) DeepCopy() *SqlActionSpec { - if in == nil { - return nil - } - out := new(SqlActionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SqlActionStatus) DeepCopyInto(out *SqlActionStatus) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SqlActionStatus. -func (in *SqlActionStatus) DeepCopy() *SqlActionStatus { - if in == nil { - return nil - } - out := new(SqlActionStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SqlDatabase) DeepCopyInto(out *SqlDatabase) { *out = *in diff --git a/config/crd/bases/azure.microsoft.com_sqlactions.yaml b/config/crd/bases/azure.microsoft.com_sqlactions.yaml deleted file mode 100644 index 27d94ae713e..00000000000 --- a/config/crd/bases/azure.microsoft.com_sqlactions.yaml +++ /dev/null @@ -1,440 +0,0 @@ - ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - creationTimestamp: null - name: sqlactions.azure.microsoft.com -spec: - group: azure.microsoft.com - names: - kind: SqlAction - plural: sqlactions - scope: "" - subresources: - status: {} - validation: - openAPIV3Schema: - description: SqlAction is the Schema for the sqlactions API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' - type: string - metadata: - description: ObjectMeta is metadata that all persisted resources must have, - which includes all objects users must create. - properties: - annotations: - additionalProperties: - type: string - description: 'Annotations is an unstructured key value map stored with - a resource that may be set by external tools to store and retrieve - arbitrary metadata. They are not queryable and should be preserved - when modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations' - type: object - clusterName: - description: The name of the cluster which the object belongs to. This - is used to distinguish resources with same name and namespace in different - clusters. This field is not set anywhere right now and apiserver is - going to ignore it if set in create or update request. - type: string - creationTimestamp: - description: "CreationTimestamp is a timestamp representing the server - time when this object was created. It is not guaranteed to be set - in happens-before order across separate operations. Clients may not - set this value. It is represented in RFC3339 form and is in UTC. \n - Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" - format: date-time - type: string - deletionGracePeriodSeconds: - description: Number of seconds allowed for this object to gracefully - terminate before it will be removed from the system. Only set when - deletionTimestamp is also set. May only be shortened. Read-only. - format: int64 - type: integer - deletionTimestamp: - description: "DeletionTimestamp is RFC 3339 date and time at which this - resource will be deleted. This field is set by the server when a graceful - deletion is requested by the user, and is not directly settable by - a client. The resource is expected to be deleted (no longer visible - from resource lists, and not reachable by name) after the time in - this field, once the finalizers list is empty. As long as the finalizers - list contains items, deletion is blocked. Once the deletionTimestamp - is set, this value may not be unset or be set further into the future, - although it may be shortened or the resource may be deleted prior - to this time. For example, a user may request that a pod is deleted - in 30 seconds. The Kubelet will react by sending a graceful termination - signal to the containers in the pod. After that 30 seconds, the Kubelet - will send a hard termination signal (SIGKILL) to the container and - after cleanup, remove the pod from the API. In the presence of network - partitions, this object may still exist after this timestamp, until - an administrator or automated process can determine the resource is - fully terminated. If not set, graceful deletion of the object has - not been requested. \n Populated by the system when a graceful deletion - is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" - format: date-time - type: string - finalizers: - description: Must be empty before the object is deleted from the registry. - Each entry is an identifier for the responsible component that will - remove the entry from the list. If the deletionTimestamp of the object - is non-nil, entries in this list can only be removed. - items: - type: string - type: array - generateName: - description: "GenerateName is an optional prefix, used by the server, - to generate a unique name ONLY IF the Name field has not been provided. - If this field is used, the name returned to the client will be different - than the name passed. This value will also be combined with a unique - suffix. The provided value has the same validation rules as the Name - field, and may be truncated by the length of the suffix required to - make the value unique on the server. \n If this field is specified - and the generated name exists, the server will NOT return a 409 - - instead, it will either return 201 Created or 500 with Reason ServerTimeout - indicating a unique name could not be found in the time allotted, - and the client should retry (optionally after the time indicated in - the Retry-After header). \n Applied only if Name is not specified. - More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency" - type: string - generation: - description: A sequence number representing a specific generation of - the desired state. Populated by the system. Read-only. - format: int64 - type: integer - initializers: - description: "An initializer is a controller which enforces some system - invariant at object creation time. This field is a list of initializers - that have not yet acted on this object. If nil or empty, this object - has been completely initialized. Otherwise, the object is considered - uninitialized and is hidden (in list/watch and get calls) from clients - that haven't explicitly asked to observe uninitialized objects. \n - When an object is created, the system will populate this list with - the current set of initializers. Only privileged users may set or - modify this list. Once it is empty, it may not be modified further - by any user. \n DEPRECATED - initializers are an alpha field and will - be removed in v1.15." - properties: - pending: - description: Pending is a list of initializers that must execute - in order before this object is visible. When the last pending - initializer is removed, and no failing result is set, the initializers - struct will be set to nil and the object is considered as initialized - and visible to all clients. - items: - description: Initializer is information about an initializer that - has not yet completed. - properties: - name: - description: name of the process that is responsible for initializing - this object. - type: string - required: - - name - type: object - type: array - result: - description: If result is set with the Failure field, the object - will be persisted to storage and then deleted, ensuring that other - clients can observe the deletion. - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this - representation of an object. Servers should convert recognized - schemas to the latest internal value, and may reject unrecognized - values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources' - type: string - code: - description: Suggested HTTP return code for this status, 0 if - not set. - format: int32 - type: integer - details: - description: Extended data associated with the reason. Each - reason may define its own extended details. This field is - optional and the data returned is not guaranteed to conform - to any schema except that defined by the reason type. - properties: - causes: - description: The Causes array includes more details associated - with the StatusReason failure. Not all StatusReasons may - provide detailed causes. - items: - description: StatusCause provides more information about - an api.Status failure, including cases when multiple - errors are encountered. - properties: - field: - description: "The field of the resource that has caused - this error, as named by its JSON serialization. - May include dot and postfix notation for nested - attributes. Arrays are zero-indexed. Fields may - appear more than once in an array of causes due - to fields having multiple errors. Optional. \n Examples: - \ \"name\" - the field \"name\" on the current - resource \"items[0].name\" - the field \"name\" - on the first array entry in \"items\"" - type: string - message: - description: A human-readable description of the cause - of the error. This field may be presented as-is - to a reader. - type: string - reason: - description: A machine-readable description of the - cause of the error. If this value is empty there - is no information available. - type: string - type: object - type: array - group: - description: The group attribute of the resource associated - with the status StatusReason. - type: string - kind: - description: 'The kind attribute of the resource associated - with the status StatusReason. On some operations may differ - from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' - type: string - name: - description: The name attribute of the resource associated - with the status StatusReason (when there is a single name - which can be described). - type: string - retryAfterSeconds: - description: If specified, the time in seconds before the - operation should be retried. Some errors may indicate - the client must take an alternate action - for those errors - this field may indicate how long to wait before taking - the alternate action. - format: int32 - type: integer - uid: - description: 'UID of the resource. (when there is a single - resource which can be described). More info: http://kubernetes.io/docs/user-guide/identifiers#uids' - type: string - type: object - kind: - description: 'Kind is a string value representing the REST resource - this object represents. Servers may infer this from the endpoint - the client submits requests to. Cannot be updated. In CamelCase. - More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' - type: string - message: - description: A human-readable description of the status of this - operation. - type: string - metadata: - description: 'Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' - properties: - continue: - description: continue may be set if the user set a limit - on the number of items returned, and indicates that the - server has more data available. The value is opaque and - may be used to issue another request to the endpoint that - served this list to retrieve the next set of available - objects. Continuing a consistent list may not be possible - if the server configuration has changed or more than a - few minutes have passed. The resourceVersion field returned - when using this continue value will be identical to the - value in the first response, unless you have received - this token from an error message. - type: string - resourceVersion: - description: 'String that identifies the server''s internal - version of this object that can be used by clients to - determine when objects have changed. Value must be treated - as opaque by clients and passed unmodified back to the - server. Populated by the system. Read-only. More info: - https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency' - type: string - selfLink: - description: selfLink is a URL representing this object. - Populated by the system. Read-only. - type: string - type: object - reason: - description: A machine-readable description of why this operation - is in the "Failure" status. If this value is empty there is - no information available. A Reason clarifies an HTTP status - code but does not override it. - type: string - status: - description: 'Status of the operation. One of: "Success" or - "Failure". More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status' - type: string - type: object - required: - - pending - type: object - labels: - additionalProperties: - type: string - description: 'Map of string keys and values that can be used to organize - and categorize (scope and select) objects. May match selectors of - replication controllers and services. More info: http://kubernetes.io/docs/user-guide/labels' - type: object - managedFields: - description: "ManagedFields maps workflow-id and version to the set - of fields that are managed by that workflow. This is mostly for internal - housekeeping, and users typically shouldn't need to set or understand - this field. A workflow can be the user's name, a controller's name, - or the name of a specific apply path like \"ci-cd\". The set of fields - is always in the version that the workflow used when modifying the - object. \n This field is alpha and can be changed or removed without - notice." - items: - description: ManagedFieldsEntry is a workflow-id, a FieldSet and the - group version of the resource that the fieldset applies to. - properties: - apiVersion: - description: APIVersion defines the version of this resource that - this field set applies to. The format is "group/version" just - like the top-level APIVersion field. It is necessary to track - the version of a field set because it cannot be automatically - converted. - type: string - fields: - additionalProperties: true - description: Fields identifies a set of fields. - type: object - manager: - description: Manager is an identifier of the workflow managing - these fields. - type: string - operation: - description: Operation is the type of operation which lead to - this ManagedFieldsEntry being created. The only valid values - for this field are 'Apply' and 'Update'. - type: string - time: - description: Time is timestamp of when these fields were set. - It should always be empty if Operation is 'Apply' - format: date-time - type: string - type: object - type: array - name: - description: 'Name must be unique within a namespace. Is required when - creating resources, although some resources may allow a client to - request the generation of an appropriate name automatically. Name - is primarily intended for creation idempotence and configuration definition. - Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names' - type: string - namespace: - description: "Namespace defines the space within each name must be unique. - An empty namespace is equivalent to the \"default\" namespace, but - \"default\" is the canonical representation. Not all objects are required - to be scoped to a namespace - the value of this field for those objects - will be empty. \n Must be a DNS_LABEL. Cannot be updated. More info: - http://kubernetes.io/docs/user-guide/namespaces" - type: string - ownerReferences: - description: List of objects depended by this object. If ALL objects - in the list have been deleted, this object will be garbage collected. - If this object is managed by a controller, then an entry in this list - will point to this controller, with the controller field set to true. - There cannot be more than one managing controller. - items: - description: OwnerReference contains enough information to let you - identify an owning object. An owning object must be in the same - namespace as the dependent, or be cluster-scoped, so there is no - namespace field. - properties: - apiVersion: - description: API version of the referent. - type: string - blockOwnerDeletion: - description: If true, AND if the owner has the "foregroundDeletion" - finalizer, then the owner cannot be deleted from the key-value - store until this reference is removed. Defaults to false. To - set this field, a user needs "delete" permission of the owner, - otherwise 422 (Unprocessable Entity) will be returned. - type: boolean - controller: - description: If true, this reference points to the managing controller. - type: boolean - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names' - type: string - uid: - description: 'UID of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#uids' - type: string - required: - - apiVersion - - kind - - name - - uid - type: object - type: array - resourceVersion: - description: "An opaque value that represents the internal version of - this object that can be used by clients to determine when objects - have changed. May be used for optimistic concurrency, change detection, - and the watch operation on a resource or set of resources. Clients - must treat these values as opaque and passed unmodified back to the - server. They may only be valid for a particular resource or set of - resources. \n Populated by the system. Read-only. Value must be treated - as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency" - type: string - selfLink: - description: SelfLink is a URL representing this object. Populated by - the system. Read-only. - type: string - uid: - description: "UID is the unique in time and space value for this object. - It is typically generated by the server on successful creation of - a resource and is not allowed to change on PUT operations. \n Populated - by the system. Read-only. More info: http://kubernetes.io/docs/user-guide/identifiers#uids" - type: string - type: object - spec: - description: SqlActionSpec defines the desired state of SqlAction - properties: - actionname: - type: string - resourcegroup: - description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file' - type: string - servername: - type: string - required: - - actionname - - resourcegroup - - servername - type: object - status: - description: SqlActionStatus defines the observed state of SqlAction - properties: - provisioned: - type: boolean - provisioning: - description: 'INSERT ADDITIONAL STATUS FIELD - define observed state - of cluster Important: Run "make" to regenerate code after modifying - this file' - type: boolean - state: - type: string - type: object - type: object - versions: - - name: v1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/config/crd/bases/azure.microsoft.com_sqlfirewallrules.yaml b/config/crd/bases/azure.microsoft.com_sqlfirewallrules.yaml index f2aa3d7208c..64463bcb3da 100644 --- a/config/crd/bases/azure.microsoft.com_sqlfirewallrules.yaml +++ b/config/crd/bases/azure.microsoft.com_sqlfirewallrules.yaml @@ -403,14 +403,16 @@ spec: properties: endipaddress: type: string - server: + location: description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster Important: Run "make" to regenerate code after modifying this file' type: string + resourcegroup: + type: string startipaddress: type: string required: - - server + - location type: object status: description: SqlFirewallRuleStatus defines the observed state of SqlFirewallRule diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 6cddca4e893..75e2efb5492 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -10,7 +10,6 @@ resources: - bases/azure.microsoft.com_eventhubnamespaces.yaml - bases/azure.microsoft.com_consumergroups.yaml - bases/azure.microsoft.com_keyvaults.yaml -- bases/azure.microsoft.com_sqlactions.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: @@ -20,7 +19,6 @@ patches: #- patches/webhook_in_eventhubnamespaces.yaml #- patches/webhook_in_consumergroups.yaml #- patches/webhook_in_keyvaults.yaml -#- patches/webhook_in_sqlactions.yaml # +kubebuilder:scaffold:crdkustomizewebhookpatch # [CAINJECTION] patches here are for enabling the CA injection for each CRD @@ -29,7 +27,6 @@ patches: #- patches/cainjection_in_eventhubnamespaces.yaml #- patches/cainjection_in_consumergroups.yaml #- patches/cainjection_in_keyvaults.yaml -#- patches/cainjection_in_sqlactions.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_sqlactions.yaml b/config/crd/patches/cainjection_in_sqlactions.yaml deleted file mode 100644 index 2e02acdc74c..00000000000 --- a/config/crd/patches/cainjection_in_sqlactions.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -# CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - certmanager.k8s.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: sqlactions.azure.microsoft.com diff --git a/config/crd/patches/webhook_in_sqlactions.yaml b/config/crd/patches/webhook_in_sqlactions.yaml deleted file mode 100644 index 406f6ad3d10..00000000000 --- a/config/crd/patches/webhook_in_sqlactions.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# The following patch enables conversion webhook for CRD -# CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: sqlactions.azure.microsoft.com -spec: - conversion: - strategy: Webhook - webhookClientConfig: - # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, - # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) - caBundle: Cg== - service: - namespace: system - name: webhook-service - path: /convert diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 1472a037772..11a2c57bdaf 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -9,7 +9,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - keyvaults + - cosmosdbs verbs: - create - delete @@ -21,7 +21,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - resourcegroups/status + - eventhubnamespaces/status verbs: - get - patch @@ -29,51 +29,38 @@ rules: - apiGroups: - azure.microsoft.com resources: - - sqlservers + - keyvaults/status verbs: - - create - - delete - get - - list - patch - update - - watch - apiGroups: - azure.microsoft.com resources: - - consumergroups + - resourcegroups/status verbs: - - create - - delete - get - - list - patch - update - - watch - apiGroups: - azure.microsoft.com resources: - - cosmosdbs/status + - sqldatabases/status verbs: - get - patch - update - apiGroups: - - azure.microsoft.com + - "" resources: - - sqlactions + - events verbs: - create - - delete - - get - - list - - patch - - update - watch - apiGroups: - azure.microsoft.com resources: - - storages/status + - rediscaches/status verbs: - get - patch @@ -89,7 +76,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - rediscaches + - eventhubs verbs: - create - delete @@ -101,31 +88,43 @@ rules: - apiGroups: - azure.microsoft.com resources: - - rediscaches/status + - eventhubnamespaces verbs: + - create + - delete - get + - list - patch - update + - watch - apiGroups: - azure.microsoft.com resources: - - sqlactions/status + - keyvaults verbs: + - create + - delete - get + - list - patch - update + - watch - apiGroups: - azure.microsoft.com resources: - - sqldatabases/status + - sqlfirewallrules verbs: + - create + - delete - get + - list - patch - update + - watch - apiGroups: - - apps + - azure.microsoft.com resources: - - deployments/status + - sqlfirewallrules/status verbs: - get - patch @@ -133,7 +132,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - cosmosdbs + - storages verbs: - create - delete @@ -145,38 +144,35 @@ rules: - apiGroups: - azure.microsoft.com resources: - - eventhubs + - sqlservers/status verbs: - - create - - delete - get - - list - patch - update - - watch - apiGroups: - - azure.microsoft.com + - apps resources: - - storages + - deployments/status verbs: - - create - - delete - get - - list - patch - update - - watch - apiGroups: - - "" + - azure.microsoft.com resources: - - events + - consumergroups verbs: - create + - delete + - get + - list + - patch + - update - watch - apiGroups: - azure.microsoft.com resources: - - eventhubnamespaces + - sqlservers verbs: - create - delete @@ -188,15 +184,15 @@ rules: - apiGroups: - azure.microsoft.com resources: - - keyvaults/status + - storages/status verbs: - get - patch - update - apiGroups: - - azure.microsoft.com + - "" resources: - - resourcegroups + - secrets verbs: - create - delete @@ -208,11 +204,10 @@ rules: - apiGroups: - azure.microsoft.com resources: - - sqlfirewallrules/status + - events verbs: - - get + - create - patch - - update - apiGroups: - azure.microsoft.com resources: @@ -224,7 +219,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - sqldatabases + - rediscaches verbs: - create - delete @@ -236,19 +231,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - sqlfirewallrules - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - secrets + - sqldatabases verbs: - create - delete @@ -272,7 +255,7 @@ rules: - apiGroups: - azure.microsoft.com resources: - - eventhubnamespaces/status + - cosmosdbs/status verbs: - get - patch @@ -280,15 +263,12 @@ rules: - apiGroups: - azure.microsoft.com resources: - - sqlservers/status + - resourcegroups verbs: + - create + - delete - get + - list - patch - update -- apiGroups: - - azure.microsoft.com - resources: - - events - verbs: - - create - - patch + - watch diff --git a/config/samples/azure_v1_sqlaction.yaml b/config/samples/azure_v1_sqlaction.yaml deleted file mode 100644 index 27ebf9561ac..00000000000 --- a/config/samples/azure_v1_sqlaction.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: azure.microsoft.com/v1 -kind: SqlAction -metadata: - name: sqlaction-name -spec: - resourcegroup: resourcegroup-sample-1907 - actionname: rollcreds - servername: sqlserver-sample \ No newline at end of file diff --git a/controllers/sqlaction_controller.go b/controllers/sqlaction_controller.go deleted file mode 100644 index 4d187038610..00000000000 --- a/controllers/sqlaction_controller.go +++ /dev/null @@ -1,227 +0,0 @@ -/* - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllers - -import ( - "context" - "errors" - "fmt" - "os" - "strconv" - "strings" - "time" - - "github.com/Azure/azure-service-operator/pkg/helpers" - sql "github.com/Azure/azure-service-operator/pkg/resourcemanager/sqlclient" - "github.com/go-logr/logr" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - azurev1 "github.com/Azure/azure-service-operator/api/v1" - "github.com/Azure/azure-service-operator/pkg/errhelp" - "github.com/Azure/go-autorest/autorest/to" - v1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/record" -) - -const sqlActionFinalizerName = "sqlaction.finalizers.azure.com" - -// SqlActionReconciler reconciles a SqlAction object -type SqlActionReconciler struct { - client.Client - Log logr.Logger - Recorder record.EventRecorder - Scheme *runtime.Scheme -} - -// +kubebuilder:rbac:groups=azure.microsoft.com,resources=sqlactions,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=azure.microsoft.com,resources=sqlactions/status,verbs=get;update;patch - -// Reconcile function runs the actual reconcilation loop of the controller -func (r *SqlActionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() - log := r.Log.WithValues("sqlaction", req.NamespacedName) - - var instance azurev1.SqlAction - - 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 fetch SqlAction", "err", err.Error()) - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - if !instance.IsSubmitted() { - if err := r.reconcileExternal(&instance); err != nil { - catchIgnorable := []string{ - errhelp.AsyncOpIncompleteError, - } - if azerr, ok := err.(*errhelp.AzureError); ok { - if helpers.ContainsString(catchIgnorable, azerr.Type) { - log.Info("Requeuing as the async operation is not complete") - return ctrl.Result{ - Requeue: true, - RequeueAfter: time.Second * time.Duration(requeueAfter), - }, nil - } - } - catchNotIgnorable := []string{ - errhelp.ResourceNotFound, - errhelp.ResourceGroupNotFoundErrorCode, - } - if azerr, ok := err.(*errhelp.AzureError); ok { - if helpers.ContainsString(catchNotIgnorable, azerr.Type) { - log.Info("Not requeueing as a specified resource was not found") - return ctrl.Result{}, nil - } - } - // TODO: Add error handling for other types of errors we might encounter here - return ctrl.Result{}, fmt.Errorf("error reconciling sqlaction in azure: %v", err) - } - return ctrl.Result{}, nil - } - - r.Recorder.Event(&instance, "Normal", "Provisioned", "SqlAction "+instance.ObjectMeta.Name+" provisioned ") - return ctrl.Result{}, nil -} - -func (r *SqlActionReconciler) reconcileExternal(instance *azurev1.SqlAction) error { - ctx := context.Background() - serverName := instance.Spec.ServerName - groupName := instance.Spec.ResourceGroup - namespace := instance.Namespace - - instance.Status.Provisioning = true - instance.Status.Provisioned = false - instance.Status.Message = "SqlAction in progress" - // write information back to instance - if updateerr := r.Status().Update(ctx, instance); updateerr != nil { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") - } - - sdkClient := sql.GoSDKClient{ - Ctx: ctx, - ResourceGroupName: groupName, - ServerName: serverName, - } - - // Get the Sql Server instance that corresponds to the Server name in the spec for this action - server, err := sdkClient.GetServer() - if err != nil { - if strings.Contains(err.Error(), "ResourceGroupNotFound") { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to get instance of SqlServer: Resource group not found") - r.Log.Info("Error", "Unable to get instance of SqlServer: Resource group not found", err) - instance.Status.Message = "Resource group not found" - // write information back to instance - if updateerr := r.Status().Update(ctx, instance); updateerr != nil { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") - } - return err - } else { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to get instance of SqlServer") - r.Log.Info("Error", "Sql Server instance not found", err) - instance.Status.Message = "Sql server instance not found" - // write information back to instance - if updateerr := r.Status().Update(ctx, instance); updateerr != nil { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") - } - return err - } - } - - sdkClient.Location = *server.Location - - // rollcreds action - if strings.ToLower(instance.Spec.ActionName) == "rollcreds" { - sqlServerProperties := sql.SQLServerProperties{ - AdministratorLogin: server.ServerProperties.AdministratorLogin, - AdministratorLoginPassword: server.ServerProperties.AdministratorLoginPassword, - } - - // Generate a new password - newPassword, _ := generateRandomPassword(passwordLength) - sqlServerProperties.AdministratorLoginPassword = to.StringPtr(newPassword) - - if _, err := sdkClient.CreateOrUpdateSQLServer(sqlServerProperties); err != nil { - if !strings.Contains(err.Error(), "not complete") { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to provision or update instance") - return errhelp.NewAzureError(err) - } - } else { - r.Recorder.Event(instance, "Normal", "Provisioned", "resource request successfully submitted to Azure") - } - - // Update the k8s secret - secret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: serverName, - Namespace: namespace, - }, - Type: "Opaque", - } - - _, createOrUpdateSecretErr := controllerutil.CreateOrUpdate(context.Background(), r.Client, secret, func() error { - r.Log.Info("Creating or updating secret with SQL Server credentials") - secret.Data["password"] = []byte(*sqlServerProperties.AdministratorLoginPassword) - return nil - }) - if createOrUpdateSecretErr != nil { - r.Log.Info("Error", "CreateOrUpdateSecretErr", createOrUpdateSecretErr) - return createOrUpdateSecretErr - } - - instance.Status.Provisioning = false - instance.Status.Provisioned = true - instance.Status.Message = "SqlAction completed successfully." - - // write information back to instance - if updateerr := r.Status().Update(ctx, instance); updateerr != nil { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") - } - - // write information back to instance - if updateerr := r.Update(ctx, instance); updateerr != nil { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") - } - } else { - r.Log.Info("Error", "reconcileExternal", "Unknown action name") - - instance.Status.Message = "Unknown action name error" - - // write information back to instance - if updateerr := r.Status().Update(ctx, instance); updateerr != nil { - r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") - } - return errors.New("Unknown action name") - } - - // Add implementations for other SqlActions here (instance.Spec.ActionName) - - return nil -} - -func (r *SqlActionReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&azurev1.SqlAction{}). - Complete(r) -} diff --git a/controllers/sqlserver_controller.go b/controllers/sqlserver_controller.go index a24ecd1ef56..0764a3e3e77 100644 --- a/controllers/sqlserver_controller.go +++ b/controllers/sqlserver_controller.go @@ -17,8 +17,8 @@ package controllers import ( "context" - "errors" "fmt" + "math/rand" "strings" "time" @@ -27,7 +27,6 @@ import ( sql "github.com/Azure/azure-service-operator/pkg/resourcemanager/sqlclient" "github.com/Azure/go-autorest/autorest/to" "github.com/go-logr/logr" - "github.com/sethvargo/go-password/password" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -48,14 +47,6 @@ type SqlServerReconciler struct { Scheme *runtime.Scheme } -// Constants -const usernameLength = 8 -const passwordLength = 16 -const minUsernameAllowedLength = 8 -const maxUsernameAllowedLength = 63 -const minPasswordAllowedLength = 8 -const maxPasswordAllowedLength = 128 - // +kubebuilder:rbac:groups=azure.microsoft.com,resources=sqlservers,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=azure.microsoft.com,resources=sqlservers/status,verbs=get;update;patch @@ -126,32 +117,8 @@ func (r *SqlServerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { } */ - // Re-create secret if server is provisioned but secret doesn't exist - if instance.IsProvisioned() { - name := instance.ObjectMeta.Name - - secret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - }, - Type: "Opaque", - } - - if err := r.Get(context.Background(), types.NamespacedName{Name: name, Namespace: instance.Namespace}, secret); err != nil { - r.Log.Info("Error", "ReconcileSecret", "Server exists but secret does not, recreating now") - - // Add admin credentials to "data" block in secret - - // CreateOrUpdate secret - } - - } - if !instance.IsSubmitted() { r.Recorder.Event(&instance, "Normal", "Submitting", "starting resource reconciliation") - // TODO: Add error handling for cases where username or password are invalid: - // https://docs.microsoft.com/en-us/rest/api/sql/servers/createorupdate#response if err := r.reconcileExternal(&instance); err != nil { catch := []string{ errhelp.ParentNotFoundErrorCode, @@ -212,25 +179,25 @@ func (r *SqlServerReconciler) reconcileExternal(instance *azurev1.SqlServer) err } // Check to see if secret already exists for admin username/password - secret, _ := r.GetOrPrepareSecret(instance) + secret := r.GetOrPrepareSecret(instance) sqlServerProperties := sql.SQLServerProperties{ AdministratorLogin: to.StringPtr(string(secret.Data["username"])), AdministratorLoginPassword: to.StringPtr(string(secret.Data["password"])), } // create the sql server - instance.Status.Provisioning = true + //instance.Status.Provisioning = true if _, err := sdkClient.CreateOrUpdateSQLServer(sqlServerProperties); err != nil { if !strings.Contains(err.Error(), "not complete") { r.Recorder.Event(instance, "Warning", "Failed", "Unable to provision or update instance") return errhelp.NewAzureError(err) } } else { - r.Recorder.Event(instance, "Normal", "Provisioned", "resource request successfully submitted to Azure") + r.Recorder.Event(instance, "Normal", "Provisioned", "resource request successfully dubmitted to Azure") } _, createOrUpdateSecretErr := controllerutil.CreateOrUpdate(context.Background(), r.Client, secret, func() error { - r.Log.Info("Creating or updating secret with SQL Server credentials") + r.Log.Info("mutating secret bundle") innerErr := controllerutil.SetControllerReference(instance, secret, r.Scheme) if innerErr != nil { return innerErr @@ -241,6 +208,8 @@ func (r *SqlServerReconciler) reconcileExternal(instance *azurev1.SqlServer) err return createOrUpdateSecretErr } + instance.Status.Provisioning = true + // write information back to instance if updateerr := r.Status().Update(ctx, instance); updateerr != nil { r.Recorder.Event(instance, "Warning", "Failed", "Unable to update instance") @@ -313,7 +282,7 @@ func (r *SqlServerReconciler) deleteExternal(instance *azurev1.SqlServer) error return nil } -func (r *SqlServerReconciler) GetOrPrepareSecret(instance *azurev1.SqlServer) (*v1.Secret, error) { +func (r *SqlServerReconciler) GetOrPrepareSecret(instance *azurev1.SqlServer) *v1.Secret { name := instance.ObjectMeta.Name secret := &v1.Secret{ @@ -321,78 +290,33 @@ func (r *SqlServerReconciler) GetOrPrepareSecret(instance *azurev1.SqlServer) (* Name: name, Namespace: instance.Namespace, }, - // Needed to avoid nil map error Data: map[string][]byte{ - "username": []byte(""), - "fullyqualifiedusername": []byte(""), - "password": []byte(""), - "sqlservername": []byte(""), - "fullyqualifiedservername": []byte(""), + "username": []byte(generateRandomString(8)), + "password": []byte(generateRandomString(16)), + "sqlservernamespace": []byte(instance.Namespace), + "sqlservername": []byte(name), }, Type: "Opaque", } - randomUsername, usernameErr := generateRandomUsername(usernameLength) - if usernameErr != nil { - return secret, usernameErr - } - - randomPassword, passwordErr := generateRandomPassword(passwordLength) - if passwordErr != nil { - return secret, passwordErr - } - - usernameSuffix := "@" + name - servernameSuffix := ".database.windows.net" - fullyQualifiedAdminUsername := randomUsername + usernameSuffix // "@"" - fullyQualifiedServername := name + servernameSuffix // ".database.windows.net" - - secret.Data["username"] = []byte(randomUsername) - secret.Data["fullyqualifiedusername"] = []byte(fullyQualifiedAdminUsername) - secret.Data["password"] = []byte(randomPassword) - secret.Data["sqlservername"] = []byte(name) - secret.Data["fullyqualifiedservername"] = []byte(fullyQualifiedServername) - if err := r.Get(context.Background(), types.NamespacedName{Name: name, Namespace: instance.Namespace}, secret); err == nil { r.Log.Info("secret already exists, pulling creds now") } - return secret, nil -} - -// helper function to generate random username for sql server -func generateRandomUsername(n int) (string, error) { - if n < minUsernameAllowedLength || n > maxUsernameAllowedLength { - return "", errors.New("Username length should be between 8 and 63 characters.") - } - - // Generate a username that is n characters long, with n/2 digits and 0 symbols (not allowed), - // allowing only lower case letters (upper case not allowed), and disallowing repeat characters. - res, err := password.Generate(n, (n / 2), 0, true, false) - if err != nil { - return "", err - } - - return res, nil + return secret } -// helper function to generate random password for sql server -func generateRandomPassword(n int) (string, error) { - if n < minPasswordAllowedLength || n > maxPasswordAllowedLength { - return "", errors.New("Password length must be between 8 and 128 characters.") - } +// helper function to generate username/password for secrets +func generateRandomString(n int) string { + rand.Seed(time.Now().UnixNano()) - // Math - Generate a password where: 1/3 of the # of chars are digits, 1/3 of the # of chars are symbols, - // and the remaining 1/3 is a mix of upper- and lower-case letters - digits := n / 3 - symbols := n / 3 + const characterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+-=<>" - // Generate a password that is n characters long, with # of digits and symbols described above, - // allowing upper and lower case letters, and disallowing repeat characters. - res, err := password.Generate(n, digits, symbols, false, false) - if err != nil { - return "", err + // TODO: add logic to enforce password policy rules for sql server + b := make([]byte, n) + for i := range b { + b[i] = characterBytes[rand.Intn(len(characterBytes))] } - return res, nil + return string(b) } diff --git a/main.go b/main.go index 82f1d3e8176..a365913aca2 100644 --- a/main.go +++ b/main.go @@ -196,15 +196,6 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "SqlFirewallRule") os.Exit(1) } - if err = (&controllers.SqlActionReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("SqlAction"), - Recorder: mgr.GetEventRecorderFor("SqlAction-controller"), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "SqlAction") - os.Exit(1) - } // +kubebuilder:scaffold:builder setupLog.Info("starting manager") diff --git a/pkg/errhelp/errhelp.go b/pkg/errhelp/errhelp.go index d90e04ffe90..5952a219f21 100644 --- a/pkg/errhelp/errhelp.go +++ b/pkg/errhelp/errhelp.go @@ -28,8 +28,3 @@ func IsAsynchronousOperationNotComplete(err error) bool { func IsStatusCode204(err error) bool { return strings.Contains(err.Error(), "StatusCode=204") } - -// IsResourceNotFound checks if error reports that a referenced resource is not found -func IsResourceNotFound(err error) bool { - return strings.Contains(err.Error(), "ResourceNotFound") -} diff --git a/pkg/resourcemanager/sqlclient/sqlclient_godsk.go b/pkg/resourcemanager/sqlclient/sqlclient_godsk.go index 364ffa8e1c4..107beff1b4c 100644 --- a/pkg/resourcemanager/sqlclient/sqlclient_godsk.go +++ b/pkg/resourcemanager/sqlclient/sqlclient_godsk.go @@ -113,13 +113,17 @@ func (sdk GoSDKClient) CreateOrUpdateDB(properties SQLDatabaseProperties) (sql.D }) } -// GetDB retrieves a database -func (sdk GoSDKClient) GetDB(databaseName string) (sql.Database, error) { - dbClient := getGoDbClient() // GetServer returns a SQL server func (sdk GoSDKClient) GetServer() (result sql.Server, err error) { serversClient := getGoServersClient() + return serversClient.Get( + sdk.Ctx, + sdk.ResourceGroupName, + sdk.ServerName, + ) +} + // GetSQLFirewallRule returns a firewall rule func (sdk GoSDKClient) GetSQLFirewallRule(ruleName string) (result sql.FirewallRule, err error) { firewallClient := getGoFirewallClient() @@ -246,14 +250,3 @@ func (sdk GoSDKClient) CheckNameAvailability() (result AvailabilityResponse, err return ToAvailabilityResponse(response), err } - -// GetServer returns a SQL server -func (sdk GoSDKClient) GetServer() (result sql.Server, err error) { - serversClient := getGoServersClient() - - return serversClient.Get( - sdk.Ctx, - sdk.ResourceGroupName, - sdk.ServerName, - ) -}