From 7e444b519263ebb13f1646fc2eaa838532193679 Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Thu, 27 Sep 2018 14:45:28 +0100 Subject: [PATCH 1/8] Added support and documentation for MYSQL Enterprise --- docs/enterprise-edition-example.md | 62 ++++ ...ter-with-3-members-enterprise-version.yaml | 7 + examples/example-enterprise-deployment.yaml | 287 ++++++++++++++++++ pkg/apis/mysql/v1alpha1/helpers.go | 2 +- pkg/options/operator/options.go | 9 +- pkg/resources/statefulsets/statefulset.go | 3 + 6 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 docs/enterprise-edition-example.md create mode 100644 examples/cluster/cluster-with-3-members-enterprise-version.yaml create mode 100644 examples/example-enterprise-deployment.yaml diff --git a/docs/enterprise-edition-example.md b/docs/enterprise-edition-example.md new file mode 100644 index 000000000..46161b3fc --- /dev/null +++ b/docs/enterprise-edition-example.md @@ -0,0 +1,62 @@ +# Enterprise edition tutorial +This tutorial will explain how to create a mysqlcluster that runs the enterprise version of mysql. + +## Prerequisites +- A Kubernetes Cluster running on Kubernetes 1.7.0+. +- The mysql-operator repository checked out locally. +- Access to a Docker registry that contains the enterprise version of mysql. + +##Create the Operator +This file bundles the creation of various resources: + +1. Custom resources +2. RBAC configuration * +3. The Operator +4. The Agent + +Section 3 of the file pulls the sql enterprise image from the docker store: `store/oracle/mysql-enterprise-server`. If you wish to pull the image from somewhere else you will need to swap out this address. +``` +kubectl apply -f examples/example-enterprise-deployment.yaml +``` + +##Create a secret with registry credentials +To be able to pull the mysql enterprise edition from docker it is necessary to provide credentials, these credentials must be supplied in the form of a Kubernetes secret. + +- The name of the secret `myregistrykey` must match the name in the `imagepullsecrets` which is found in Section 3 of the `example-enterprise-deployment.yaml`. +- The secret must be created in the same namespace as the mysqlcluster which we will make in the next step. +- If you are pulling the mysql enterprise image from a different registry then the secret must contain the relevant credentials for that registry. + +>For alternative ways to create Kubernetes secretes see their documentation on [creating secrets from docker configs](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) or [creating secrets manually](https://kubernetes.io/docs/concepts/containers/images/#creating-a-secret-with-a-docker-config). + +Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. +``` +kubectl create secret docker-registry myregistrykey \ +--docker-server=https://index.docker.io/v1/ \ +--docker-username= \ +--docker-password= \ +--docker-email= +``` +##Create your mysqlcluster +Finally, create the mysqlcluster. + +- The version to be used has been specified in the file. Without this a default version is used which is **not** guaranteed to match an available image of mysql enterprise. +- The lowest version supported by the mysql operator is **8.0.11** +- The namespace of the cluster must match the namespace of the secret we created in the previous step. This file omits namespace in the metadata so the cluster will be created in the default namespace. +``` +kubectl apply -f examples/cluster/cluster-with-3-members-enterprise-version.yaml +``` +You can now run the following command to see the newly created mysql cluster +``` +kubectl describe mysqlcluster mysql +``` + +## Clean up + +To remove the mysqlcluster and each of the components created in this tutorial, execute the following: +``` +kubectl delete -f examples/cluster/cluster-with-3-members-enterprise-version.yaml +kubectl delete secret myregistrykey +kubectl delete -f examples/example-enterprise-deployment.yaml +``` + +>*If you run into issues when creating RBAC roles see [Access controls](https://docs.cloud.oracle.com/iaas/Content/ContEng/Concepts/contengabouta]ccesscontrol.htm?) for more information. \ No newline at end of file diff --git a/examples/cluster/cluster-with-3-members-enterprise-version.yaml b/examples/cluster/cluster-with-3-members-enterprise-version.yaml new file mode 100644 index 000000000..cb78c1eba --- /dev/null +++ b/examples/cluster/cluster-with-3-members-enterprise-version.yaml @@ -0,0 +1,7 @@ +apiVersion: mysql.oracle.com/v1alpha1 +kind: Cluster +metadata: + name: mysql +spec: + members: 3 + version: "8.0.11" diff --git a/examples/example-enterprise-deployment.yaml b/examples/example-enterprise-deployment.yaml new file mode 100644 index 000000000..a593edd1e --- /dev/null +++ b/examples/example-enterprise-deployment.yaml @@ -0,0 +1,287 @@ +# 01 - Custom resources +--- +apiVersion: v1 +kind: Namespace +metadata: + name: mysql-operator +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlclusters.mysql.oracle.com +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: Cluster + singular: mysqlcluster + plural: mysqlclusters +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlbackups.mysql.oracle.com +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: Backup + singular: mysqlbackup + plural: mysqlbackups +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlrestores.mysql.oracle.com +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: Restore + singular: mysqlrestore + plural: mysqlrestores +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlbackupschedules.mysql.oracle.com +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: BackupSchedule + singular: mysqlbackupschedule + plural: mysqlbackupschedules +#02 +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mysql-operator + namespace: mysql-operator + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mysql-agent + namespace: default + +#RBAC +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: mysql-operator + namespace: mysql-operator +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: + - get + - list + - patch + - update + - watch + + - apiGroups: [""] + resources: ["secrets"] + verbs: ["create"] + + - apiGroups: [""] + resources: ["services"] + verbs: + - create + - get + - list + - watch + + - apiGroups: [""] + resources: ["events"] + verbs: + - create + - update + - patch + + - apiGroups: ["apps"] + resources: ["statefulsets"] + verbs: + - create + - get + - list + - patch + - update + - watch + + - apiGroups: ["mysql.oracle.com"] + resources: + - mysqlbackups + - mysqlbackupschedules + - mysqlclusters + - mysqlclusters/finalizers + - mysqlrestores + verbs: + - get + - list + - patch + - update + - watch + + - apiGroups: ["mysql.oracle.com"] + resources: ["mysqlbackups"] + verbs: ["create"] + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: mysql-agent + namespace: mysql-operator +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: + - get + - list + - patch + - update + - watch + + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + + - apiGroups: [""] + resources: ["events"] + verbs: + - create + - update + - patch + + - apiGroups: ["mysql.oracle.com"] + resources: + - mysqlbackups + - mysqlbackupschedules + - mysqlclusters + - mysqlclusters/finalizers + - mysqlrestores + verbs: + - get + - list + - patch + - update + - watch + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: mysql-operator + namespace: mysql-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: mysql-operator +subjects: +- kind: ServiceAccount + name: mysql-operator + namespace: mysql-operator + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: mysql-agent + namespace: mysql-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: mysql-agent +subjects: +- kind: ServiceAccount + name: mysql-agent + namespace: mysql-operator + +#03 - The operator +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: mysql-operator-config + namespace: mysql-operator + labels: + app: mysql-operator +data: + mysql-operator-config.yaml: | + images: + mysqlServer: store/oracle/mysql-enterprise-server #Enterprise sql image + mysqlAgent: iad.ocir.io/oracle/mysql-agent + imagePullSecret: + name: myregistrykey #Name of secret with docker credentials +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: mysql-operator + namespace: mysql-operator + labels: + app: mysql-operator +spec: + replicas: 1 + selector: + matchLabels: + app: mysql-operator + template: + metadata: + labels: + app: mysql-operator + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + spec: + serviceAccountName: mysql-operator + imagePullSecrets: + - name: docker-secret + volumes: + - name: mysql-operator-config-volume + configMap: + name: mysql-operator-config + containers: + - name: mysql-operator-controller + imagePullPolicy: Always + image: iad.ocir.io/oracle/mysql-operator:0.2.0 + ports: + - containerPort: 10254 + volumeMounts: + - name: mysql-operator-config-volume + mountPath: /etc/mysql-operator + args: + - --v=4 + - --mysql-agent-image=iad.ocir.io/oracle/mysql-agent + +#04 - The Agent +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mysql-agent + namespace: default + +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: mysql-agent + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: mysql-agent +subjects: +- kind: ServiceAccount + name: mysql-agent + namespace: default diff --git a/pkg/apis/mysql/v1alpha1/helpers.go b/pkg/apis/mysql/v1alpha1/helpers.go index dd9398b9d..22b76ca2c 100644 --- a/pkg/apis/mysql/v1alpha1/helpers.go +++ b/pkg/apis/mysql/v1alpha1/helpers.go @@ -50,7 +50,7 @@ func getOperatorVersionLabel(labelMap map[string]string) string { return labelMap[constants.MySQLOperatorVersionLabel] } -// EnsureDefaults will ensure that if a user omits and fields in the +// EnsureDefaults will ensure that if a user omits any fields in the // spec that are required, we set some sensible defaults. // For example a user can choose to omit the version // and number of members. diff --git a/pkg/options/operator/options.go b/pkg/options/operator/options.go index c337dfb8e..59f2d1d60 100644 --- a/pkg/options/operator/options.go +++ b/pkg/options/operator/options.go @@ -20,6 +20,8 @@ import ( "path/filepath" "time" + "k8s.io/api/core/v1" + "github.com/golang/glog" "github.com/pkg/errors" "github.com/spf13/pflag" @@ -36,8 +38,9 @@ const ( // Images is the configuration of required MySQLOperator images. Remember to configure the appropriate // credentials for the target repositories. type Images struct { - MySQLServerImage string `yaml:"mysqlServer"` - MySQLAgentImage string `yaml:"mysqlAgent"` + MySQLServerImage string `yaml:"mysqlServer"` + MySQLAgentImage string `yaml:"mysqlAgent"` + ImagePullSecret *v1.LocalObjectReference `yaml:"imagePullSecret"` } // MySQLOperatorOpts holds the options for the MySQLOperator. @@ -65,7 +68,7 @@ type MySQLOperatorOpts struct { MinResyncPeriod metav1.Duration `yaml:"minResyncPeriod"` } -// MySQLOperatorOpts will create a new MySQLOperatorOpts. If a valid +// NewMySQLOperatorOpts will create a new MySQLOperatorOpts. If a valid // config file is specified and exists, it will be used to initialise the // server. Otherwise, a default server will be created. // diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index f97436adc..85569d4f0 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -399,6 +399,9 @@ func NewForCluster(cluster *v1alpha1.Cluster, images operatoropts.Images, servic }, } + if images.ImagePullSecret != nil { + ss.Spec.Template.Spec.ImagePullSecrets = append(ss.Spec.Template.Spec.ImagePullSecrets, *images.ImagePullSecret) + } if cluster.Spec.VolumeClaimTemplate != nil { ss.Spec.VolumeClaimTemplates = append(ss.Spec.VolumeClaimTemplates, *cluster.Spec.VolumeClaimTemplate) } From e0a5ded36ec17e9b972f31a4103f37545271f5ef Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Thu, 27 Sep 2018 15:10:46 +0100 Subject: [PATCH 2/8] formatting fix --- docs/enterprise-edition-example.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/enterprise-edition-example.md b/docs/enterprise-edition-example.md index 46161b3fc..b9437fe0f 100644 --- a/docs/enterprise-edition-example.md +++ b/docs/enterprise-edition-example.md @@ -6,7 +6,7 @@ This tutorial will explain how to create a mysqlcluster that runs the enterprise - The mysql-operator repository checked out locally. - Access to a Docker registry that contains the enterprise version of mysql. -##Create the Operator +## Create the Operator This file bundles the creation of various resources: 1. Custom resources @@ -19,7 +19,7 @@ Section 3 of the file pulls the sql enterprise image from the docker store: `sto kubectl apply -f examples/example-enterprise-deployment.yaml ``` -##Create a secret with registry credentials +## Create a secret with registry credentials To be able to pull the mysql enterprise edition from docker it is necessary to provide credentials, these credentials must be supplied in the form of a Kubernetes secret. - The name of the secret `myregistrykey` must match the name in the `imagepullsecrets` which is found in Section 3 of the `example-enterprise-deployment.yaml`. @@ -36,7 +36,7 @@ kubectl create secret docker-registry myregistrykey \ --docker-password= \ --docker-email= ``` -##Create your mysqlcluster +## Create your mysqlcluster Finally, create the mysqlcluster. - The version to be used has been specified in the file. Without this a default version is used which is **not** guaranteed to match an available image of mysql enterprise. From ce721f9bdf4e903de1a46ec7ec56db635bb93942 Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Mon, 1 Oct 2018 17:13:40 +0100 Subject: [PATCH 3/8] Moved custom mysql server image from operator spec to cluster spec --- docs/development.md | 19 +- docs/enterprise-edition-example.md | 50 ++- .../cluster/cluster-enterprise-version.yaml | 10 + ...ter-with-3-members-enterprise-version.yaml | 7 - examples/example-enterprise-deployment.yaml | 287 ------------------ pkg/apis/mysql/v1alpha1/helpers.go | 5 + pkg/apis/mysql/v1alpha1/types.go | 6 + pkg/options/operator/options.go | 15 +- pkg/options/operator/options_test.go | 6 +- pkg/resources/statefulsets/statefulset.go | 6 +- 10 files changed, 60 insertions(+), 351 deletions(-) create mode 100644 examples/cluster/cluster-enterprise-version.yaml delete mode 100644 examples/cluster/cluster-with-3-members-enterprise-version.yaml delete mode 100644 examples/example-enterprise-deployment.yaml diff --git a/docs/development.md b/docs/development.md index e1c37ad04..4a04d1bc0 100644 --- a/docs/development.md +++ b/docs/development.md @@ -20,6 +20,10 @@ in the format of `$USER-TIMESTAMP`. This will need to be remembered as this is needed for a latter step or can be exported as the `$MYSQL_AGENT_VERSION` envrionment variable. +```bash +$ export MYSQL_AGENT_VERSION=$(cat dist/version.txt) +``` + ## Create a namespace Create the namespace that the operator will reside in. By default this is @@ -38,11 +42,13 @@ ServiceAccounts, ClusterRoles, and ClusterRoleBindings for the operator to function. ```bash -$ kubectl -n $USER apply \ - -f contrib/manifests/custom-resource-definitions.yaml \ - -f contrib/manifests/rbac.yaml -$ sed -e "s//${USER}/g" \ - contrib/manifests/role-binding-template.yaml | kubectl -n $USER apply -f - +$ kubectl -n $USER apply -f contrib/manifests/custom-resource-definitions.yaml +``` +```bash +$ sed -e "s//${USER}/g" contrib/manifests/rbac.yaml | kubectl -n $USER apply -f - +``` +```bash +$ sed -e "s//${USER}/g" contrib/manifests/role-binding-template.yaml | kubectl -n $USER apply -f - ``` ### Run the MySQL Operator @@ -54,9 +60,6 @@ development purposes. $ make run-dev ``` -If you did not set an envrionment variable previously, prefix this command with -`MYSQL_AGENT_VERSION=` followed by the $USER-TIMESTAMP fortmatted version. - ## Creating an InnoDB cluster For the purpose of this document, we will create a cluster with 3 members with diff --git a/docs/enterprise-edition-example.md b/docs/enterprise-edition-example.md index b9437fe0f..c7d2020f8 100644 --- a/docs/enterprise-edition-example.md +++ b/docs/enterprise-edition-example.md @@ -2,33 +2,30 @@ This tutorial will explain how to create a mysqlcluster that runs the enterprise version of mysql. ## Prerequisites -- A Kubernetes Cluster running on Kubernetes 1.7.0+. + - The mysql-operator repository checked out locally. - Access to a Docker registry that contains the enterprise version of mysql. -## Create the Operator -This file bundles the creation of various resources: +## 01 - Create the Operator +You will need to create the following: 1. Custom resources 2. RBAC configuration * 3. The Operator -4. The Agent +4. The Agent ServiceAccount & RoleBinding -Section 3 of the file pulls the sql enterprise image from the docker store: `store/oracle/mysql-enterprise-server`. If you wish to pull the image from somewhere else you will need to swap out this address. -``` -kubectl apply -f examples/example-enterprise-deployment.yaml -``` +The creation of these resources can be achieved by following the [introductory tutorial][1]; return here before creating a MySQL Cluster. -## Create a secret with registry credentials +## 02 - Create a secret with registry credentials To be able to pull the mysql enterprise edition from docker it is necessary to provide credentials, these credentials must be supplied in the form of a Kubernetes secret. -- The name of the secret `myregistrykey` must match the name in the `imagepullsecrets` which is found in Section 3 of the `example-enterprise-deployment.yaml`. -- The secret must be created in the same namespace as the mysqlcluster which we will make in the next step. +- The name of the secret `myregistrykey` must match the name in the `imagepullsecrets` which we will specify in the cluster config in step 03. +- The secret must be created in the same namespace as the MySQL Cluster which we will make in step 03. It must also be in the same namespace as the RBAC permissions created in step 01. - If you are pulling the mysql enterprise image from a different registry then the secret must contain the relevant credentials for that registry. >For alternative ways to create Kubernetes secretes see their documentation on [creating secrets from docker configs](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) or [creating secrets manually](https://kubernetes.io/docs/concepts/containers/images/#creating-a-secret-with-a-docker-config). -Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. +Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. add the `-n` flag to specify a namespace if you do not want to use the default namespace. ``` kubectl create secret docker-registry myregistrykey \ --docker-server=https://index.docker.io/v1/ \ @@ -36,27 +33,22 @@ kubectl create secret docker-registry myregistrykey \ --docker-password= \ --docker-email= ``` -## Create your mysqlcluster -Finally, create the mysqlcluster. +## 03 - Create your MySQL Cluster +Finally, create your MySQL Cluster with the required specifications entered under `spec:` -- The version to be used has been specified in the file. Without this a default version is used which is **not** guaranteed to match an available image of mysql enterprise. -- The lowest version supported by the mysql operator is **8.0.11** -- The namespace of the cluster must match the namespace of the secret we created in the previous step. This file omits namespace in the metadata so the cluster will be created in the default namespace. +- The mysqlServer field should be the path to a registry containing the enterprise edition of MySQL. +- The imagePullSecret: name: Should be the name of a Kubernetes secret in the same namespace that contains your credentials for the docker registry. +- The version to be used must be specified, without this, a default version is used which is **not** guaranteed to match an available image of MySQL Enterprise. +- The namespace of the cluster must match the namespace of the secret we created in step 02. ``` -kubectl apply -f examples/cluster/cluster-with-3-members-enterprise-version.yaml +kubectl apply -f examples/cluster/cluster-enterprise-version.yaml ``` -You can now run the following command to see the newly created mysql cluster +### Check that it is running +You can now run the following command to access the sql prompt in your MySQL Cluster, just replace `` with the namespace you created your cluster in. ``` -kubectl describe mysqlcluster mysql +sh hack/mysql.sh /mysql-0 ``` -## Clean up - -To remove the mysqlcluster and each of the components created in this tutorial, execute the following: -``` -kubectl delete -f examples/cluster/cluster-with-3-members-enterprise-version.yaml -kubectl delete secret myregistrykey -kubectl delete -f examples/example-enterprise-deployment.yaml -``` +>*If you run into issues when creating RBAC roles see [Access controls](https://docs.cloud.oracle.com/iaas/Content/ContEng/Concepts/contengabouta]ccesscontrol.htm?) for more information. ->*If you run into issues when creating RBAC roles see [Access controls](https://docs.cloud.oracle.com/iaas/Content/ContEng/Concepts/contengabouta]ccesscontrol.htm?) for more information. \ No newline at end of file +[1]: docs/tutorial.md \ No newline at end of file diff --git a/examples/cluster/cluster-enterprise-version.yaml b/examples/cluster/cluster-enterprise-version.yaml new file mode 100644 index 000000000..ee003d3e8 --- /dev/null +++ b/examples/cluster/cluster-enterprise-version.yaml @@ -0,0 +1,10 @@ +apiVersion: mysql.oracle.com/v1alpha1 +kind: Cluster +metadata: + name: mysql + namespace: default +spec: + version: "8.0.11" + mysqlServer: store/oracle/mysql-enterprise-server + imagePullSecret: + name: myregistrykey diff --git a/examples/cluster/cluster-with-3-members-enterprise-version.yaml b/examples/cluster/cluster-with-3-members-enterprise-version.yaml deleted file mode 100644 index cb78c1eba..000000000 --- a/examples/cluster/cluster-with-3-members-enterprise-version.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: mysql.oracle.com/v1alpha1 -kind: Cluster -metadata: - name: mysql -spec: - members: 3 - version: "8.0.11" diff --git a/examples/example-enterprise-deployment.yaml b/examples/example-enterprise-deployment.yaml deleted file mode 100644 index a593edd1e..000000000 --- a/examples/example-enterprise-deployment.yaml +++ /dev/null @@ -1,287 +0,0 @@ -# 01 - Custom resources ---- -apiVersion: v1 -kind: Namespace -metadata: - name: mysql-operator ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: mysqlclusters.mysql.oracle.com -spec: - group: mysql.oracle.com - version: v1alpha1 - scope: Namespaced - names: - kind: Cluster - singular: mysqlcluster - plural: mysqlclusters ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: mysqlbackups.mysql.oracle.com -spec: - group: mysql.oracle.com - version: v1alpha1 - scope: Namespaced - names: - kind: Backup - singular: mysqlbackup - plural: mysqlbackups ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: mysqlrestores.mysql.oracle.com -spec: - group: mysql.oracle.com - version: v1alpha1 - scope: Namespaced - names: - kind: Restore - singular: mysqlrestore - plural: mysqlrestores ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: mysqlbackupschedules.mysql.oracle.com -spec: - group: mysql.oracle.com - version: v1alpha1 - scope: Namespaced - names: - kind: BackupSchedule - singular: mysqlbackupschedule - plural: mysqlbackupschedules -#02 ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mysql-operator - namespace: mysql-operator - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mysql-agent - namespace: default - -#RBAC ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: mysql-operator - namespace: mysql-operator -rules: - - apiGroups: [""] - resources: ["pods"] - verbs: - - get - - list - - patch - - update - - watch - - - apiGroups: [""] - resources: ["secrets"] - verbs: ["create"] - - - apiGroups: [""] - resources: ["services"] - verbs: - - create - - get - - list - - watch - - - apiGroups: [""] - resources: ["events"] - verbs: - - create - - update - - patch - - - apiGroups: ["apps"] - resources: ["statefulsets"] - verbs: - - create - - get - - list - - patch - - update - - watch - - - apiGroups: ["mysql.oracle.com"] - resources: - - mysqlbackups - - mysqlbackupschedules - - mysqlclusters - - mysqlclusters/finalizers - - mysqlrestores - verbs: - - get - - list - - patch - - update - - watch - - - apiGroups: ["mysql.oracle.com"] - resources: ["mysqlbackups"] - verbs: ["create"] - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: mysql-agent - namespace: mysql-operator -rules: - - apiGroups: [""] - resources: ["pods"] - verbs: - - get - - list - - patch - - update - - watch - - - apiGroups: [""] - resources: ["secrets"] - verbs: ["get"] - - - apiGroups: [""] - resources: ["events"] - verbs: - - create - - update - - patch - - - apiGroups: ["mysql.oracle.com"] - resources: - - mysqlbackups - - mysqlbackupschedules - - mysqlclusters - - mysqlclusters/finalizers - - mysqlrestores - verbs: - - get - - list - - patch - - update - - watch - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: mysql-operator - namespace: mysql-operator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: mysql-operator -subjects: -- kind: ServiceAccount - name: mysql-operator - namespace: mysql-operator - ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: mysql-agent - namespace: mysql-operator -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: mysql-agent -subjects: -- kind: ServiceAccount - name: mysql-agent - namespace: mysql-operator - -#03 - The operator ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: mysql-operator-config - namespace: mysql-operator - labels: - app: mysql-operator -data: - mysql-operator-config.yaml: | - images: - mysqlServer: store/oracle/mysql-enterprise-server #Enterprise sql image - mysqlAgent: iad.ocir.io/oracle/mysql-agent - imagePullSecret: - name: myregistrykey #Name of secret with docker credentials ---- -apiVersion: apps/v1beta1 -kind: Deployment -metadata: - name: mysql-operator - namespace: mysql-operator - labels: - app: mysql-operator -spec: - replicas: 1 - selector: - matchLabels: - app: mysql-operator - template: - metadata: - labels: - app: mysql-operator - annotations: - prometheus.io/scrape: "true" - prometheus.io/port: "8080" - spec: - serviceAccountName: mysql-operator - imagePullSecrets: - - name: docker-secret - volumes: - - name: mysql-operator-config-volume - configMap: - name: mysql-operator-config - containers: - - name: mysql-operator-controller - imagePullPolicy: Always - image: iad.ocir.io/oracle/mysql-operator:0.2.0 - ports: - - containerPort: 10254 - volumeMounts: - - name: mysql-operator-config-volume - mountPath: /etc/mysql-operator - args: - - --v=4 - - --mysql-agent-image=iad.ocir.io/oracle/mysql-agent - -#04 - The Agent ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mysql-agent - namespace: default - ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: mysql-agent - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: mysql-agent -subjects: -- kind: ServiceAccount - name: mysql-agent - namespace: default diff --git a/pkg/apis/mysql/v1alpha1/helpers.go b/pkg/apis/mysql/v1alpha1/helpers.go index 22b76ca2c..15582df78 100644 --- a/pkg/apis/mysql/v1alpha1/helpers.go +++ b/pkg/apis/mysql/v1alpha1/helpers.go @@ -27,6 +27,7 @@ const ( // maxBaseServerID is the maximum safe value for BaseServerID calculated // as max MySQL server_id value - max Replication Group size. maxBaseServerID uint32 = 4294967295 - 9 + mysqlServer = "mysql/mysql-server" ) const ( @@ -67,6 +68,10 @@ func (c *Cluster) EnsureDefaults() *Cluster { c.Spec.Version = defaultVersion } + if c.Spec.MySQLServerImage == "" { + c.Spec.MySQLServerImage = mysqlServer + } + return c } diff --git a/pkg/apis/mysql/v1alpha1/types.go b/pkg/apis/mysql/v1alpha1/types.go index 7d028c961..cd09a4404 100644 --- a/pkg/apis/mysql/v1alpha1/types.go +++ b/pkg/apis/mysql/v1alpha1/types.go @@ -15,6 +15,7 @@ package v1alpha1 import ( + "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -27,6 +28,11 @@ const MinimumMySQLVersion = "8.0.11" type ClusterSpec struct { // Version defines the MySQL Docker image version. Version string `json:"version"` + // MySQLServerImage defines the image to be pulled for the mysqlServer. + MySQLServerImage string `json:"mysqlServer"` + // ImagePullSecret defines the name of the secret that contains the + // required credentials for pulling the MySQLServerImage. + ImagePullSecret *v1.LocalObjectReference `json:"imagePullSecret"` // Members defines the number of MySQL instances in a cluster Members int32 `json:"members,omitempty"` // BaseServerID defines the base number used to create unique server_id diff --git a/pkg/options/operator/options.go b/pkg/options/operator/options.go index 59f2d1d60..e7cfd43c1 100644 --- a/pkg/options/operator/options.go +++ b/pkg/options/operator/options.go @@ -20,8 +20,6 @@ import ( "path/filepath" "time" - "k8s.io/api/core/v1" - "github.com/golang/glog" "github.com/pkg/errors" "github.com/spf13/pflag" @@ -31,16 +29,13 @@ import ( ) const ( - mysqlServer = "mysql/mysql-server" - mysqlAgent = "iad.ocir.io/oracle/mysql-agent" + mysqlAgent = "iad.ocir.io/oracle/mysql-agent" ) // Images is the configuration of required MySQLOperator images. Remember to configure the appropriate -// credentials for the target repositories. +// credentials for the target repositories. Image for mysqlServer is specified in ClusterSpec type Images struct { - MySQLServerImage string `yaml:"mysqlServer"` - MySQLAgentImage string `yaml:"mysqlAgent"` - ImagePullSecret *v1.LocalObjectReference `yaml:"imagePullSecret"` + MySQLAgentImage string `yaml:"mysqlAgent"` } // MySQLOperatorOpts holds the options for the MySQLOperator. @@ -109,9 +104,6 @@ func (s *MySQLOperatorOpts) EnsureDefaults() { if &s.Images == nil { s.Images = Images{} } - if s.Images.MySQLServerImage == "" { - s.Images.MySQLServerImage = mysqlServer - } if s.Images.MySQLAgentImage == "" { s.Images.MySQLAgentImage = mysqlAgent } @@ -125,7 +117,6 @@ func (s *MySQLOperatorOpts) AddFlags(fs *pflag.FlagSet) *pflag.FlagSet { fs.StringVar(&s.KubeConfig, "kubeconfig", s.KubeConfig, "Path to Kubeconfig file with authorization and master location information.") fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig).") fs.StringVar(&s.Namespace, "namespace", metav1.NamespaceAll, "The namespace for which the MySQL operator manages MySQL clusters. Defaults to all.") - fs.StringVar(&s.Images.MySQLServerImage, "mysql-server-image", s.Images.MySQLServerImage, "The name of the target 'mysql-server' image. Defaults to: mysql/mysql-server.") fs.StringVar(&s.Images.MySQLAgentImage, "mysql-agent-image", s.Images.MySQLAgentImage, "The name of the target 'mysql-agent' image. Defaults to: iad.ocir.io/oracle/mysql-agent.") fs.DurationVar(&s.MinResyncPeriod.Duration, "min-resync-period", s.MinResyncPeriod.Duration, "The resync period in reflectors will be random between MinResyncPeriod and 2*MinResyncPeriod.") return fs diff --git a/pkg/options/operator/options_test.go b/pkg/options/operator/options_test.go index 95a4b1132..a9c77b676 100644 --- a/pkg/options/operator/options_test.go +++ b/pkg/options/operator/options_test.go @@ -36,9 +36,6 @@ func assertRequiredDefaults(t *testing.T, s MySQLOperatorOpts) { if &s.Images == nil { t.Error("MySQLOperatorServer.Images: was nil, expected a valid configuration.") } - if s.Images.MySQLServerImage != mysqlServer { - t.Errorf("MySQLOperatorServer.Images.MySQLServerImage: was '%s', expected '%s'.", s.Images.MySQLServerImage, mysqlServer) - } if s.Images.MySQLAgentImage != mysqlAgent { t.Errorf("MySQLOperatorServer.Images.MySQLAgentImage: was '%s', expected '%s'.", s.Images.MySQLAgentImage, mysqlAgent) } @@ -66,8 +63,7 @@ func mockMySQLOperatorOpts() MySQLOperatorOpts { Master: "some-master", Hostname: "some-hostname", Images: Images{ - MySQLServerImage: "some-mysql-img", - MySQLAgentImage: "some-agent-img", + MySQLAgentImage: "some-agent-img", }, MinResyncPeriod: v1.Duration{Duration: 42}, } diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index 85569d4f0..1eb4cb8fc 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -345,7 +345,7 @@ func NewForCluster(cluster *v1alpha1.Cluster, images operatoropts.Images, servic } containers := []v1.Container{ - mysqlServerContainer(cluster, images.MySQLServerImage, rootPassword, members, baseServerID), + mysqlServerContainer(cluster, cluster.Spec.MySQLServerImage, rootPassword, members, baseServerID), mysqlAgentContainer(cluster, images.MySQLAgentImage, rootPassword, members)} podLabels := map[string]string{ @@ -399,8 +399,8 @@ func NewForCluster(cluster *v1alpha1.Cluster, images operatoropts.Images, servic }, } - if images.ImagePullSecret != nil { - ss.Spec.Template.Spec.ImagePullSecrets = append(ss.Spec.Template.Spec.ImagePullSecrets, *images.ImagePullSecret) + if cluster.Spec.ImagePullSecret != nil { + ss.Spec.Template.Spec.ImagePullSecrets = append(ss.Spec.Template.Spec.ImagePullSecrets, *cluster.Spec.ImagePullSecret) } if cluster.Spec.VolumeClaimTemplate != nil { ss.Spec.VolumeClaimTemplates = append(ss.Spec.VolumeClaimTemplates, *cluster.Spec.VolumeClaimTemplate) From d5d2694c2c5e6b5a53e776549c78f54c105750a6 Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Tue, 2 Oct 2018 12:18:16 +0100 Subject: [PATCH 4/8] Added unit tests for ensuring server image default --- pkg/apis/mysql/v1alpha1/cluster_test.go | 4 +- pkg/apis/mysql/v1alpha1/helpers.go | 11 +-- .../statefulsets/statefulset_test.go | 70 +++++-------------- 3 files changed, 27 insertions(+), 58 deletions(-) diff --git a/pkg/apis/mysql/v1alpha1/cluster_test.go b/pkg/apis/mysql/v1alpha1/cluster_test.go index eb01c7703..80e74ebf7 100644 --- a/pkg/apis/mysql/v1alpha1/cluster_test.go +++ b/pkg/apis/mysql/v1alpha1/cluster_test.go @@ -85,8 +85,8 @@ func TestDefaultVersion(t *testing.T) { cluster := &Cluster{} cluster.EnsureDefaults() - if cluster.Spec.Version != defaultVersion { - t.Errorf("Expected default version to be %s but got %s", defaultVersion, cluster.Spec.Version) + if cluster.Spec.Version != DefaultVersion { + t.Errorf("Expected default version to be %s but got %s", DefaultVersion, cluster.Spec.Version) } } diff --git a/pkg/apis/mysql/v1alpha1/helpers.go b/pkg/apis/mysql/v1alpha1/helpers.go index 15582df78..f68f0b7e8 100644 --- a/pkg/apis/mysql/v1alpha1/helpers.go +++ b/pkg/apis/mysql/v1alpha1/helpers.go @@ -20,14 +20,15 @@ import ( ) const ( - // The default MySQL version to use if not specified explicitly by user - defaultVersion = "8.0.12" + // DefaultVersion is the MySQL version to use if not specified explicitly by user + DefaultVersion = "8.0.12" defaultMembers = 3 defaultBaseServerID = 1000 // maxBaseServerID is the maximum safe value for BaseServerID calculated // as max MySQL server_id value - max Replication Group size. maxBaseServerID uint32 = 4294967295 - 9 - mysqlServer = "mysql/mysql-server" + // MysqlServer is the image to use if no image is specified explicitly by the user. + MysqlServer = "mysql/mysql-server" ) const ( @@ -65,11 +66,11 @@ func (c *Cluster) EnsureDefaults() *Cluster { } if c.Spec.Version == "" { - c.Spec.Version = defaultVersion + c.Spec.Version = DefaultVersion } if c.Spec.MySQLServerImage == "" { - c.Spec.MySQLServerImage = mysqlServer + c.Spec.MySQLServerImage = MysqlServer } return c diff --git a/pkg/resources/statefulsets/statefulset_test.go b/pkg/resources/statefulsets/statefulset_test.go index 650d14d0c..960d8b0aa 100644 --- a/pkg/resources/statefulsets/statefulset_test.go +++ b/pkg/resources/statefulsets/statefulset_test.go @@ -18,9 +18,10 @@ import ( "reflect" "testing" + "k8s.io/api/core/v1" + "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/oracle/mysql-operator/pkg/apis/mysql/v1alpha1" @@ -223,67 +224,34 @@ func TestClusterWithTolerations(t *testing.T) { } } -func TestClusterWithResourceRequirements(t *testing.T) { - mysqlServerResourceRequirements := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("2"), - corev1.ResourceMemory: resource.MustParse("2Gi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("1Gi"), - }, - } - - mysqlAgentResourceRequirements := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("512Mi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("100m"), - corev1.ResourceMemory: resource.MustParse("128Mi"), - }, - } - +func TestClusterEnterpriseImage(t *testing.T) { cluster := &v1alpha1.Cluster{ Spec: v1alpha1.ClusterSpec{ - Resources: &v1alpha1.Resources{ - Server: &mysqlServerResourceRequirements, - Agent: &mysqlAgentResourceRequirements, + MySQLServerImage: "some/image/path", + ImagePullSecret: &v1.LocalObjectReference{ + Name: "someSecretName", }, }, } + cluster.EnsureDefaults() statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") - assert.Equal(t, mysqlServerResourceRequirements, statefulSet.Spec.Template.Spec.Containers[0].Resources, "MySQL-Server container resource requirements do not match expected.") - assert.Equal(t, mysqlAgentResourceRequirements, statefulSet.Spec.Template.Spec.Containers[1].Resources, "MySQL-Agent container resource requirements do not match expected.") -} + pullSecrets := statefulSet.Spec.Template.Spec.ImagePullSecrets + ps := pullSecrets[len(pullSecrets)-1] + si := statefulSet.Spec.Template.Spec.Containers[0].Image -func TestClusterWithOnlyMysqlServerResourceRequirements(t *testing.T) { - mysqlServerResourceRequirements := corev1.ResourceRequirements{ - Limits: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("2"), - corev1.ResourceMemory: resource.MustParse("2Gi"), - }, - Requests: corev1.ResourceList{ - corev1.ResourceCPU: resource.MustParse("500m"), - corev1.ResourceMemory: resource.MustParse("1Gi"), - }, - } + assert.Equal(t, "someSecretName", ps.Name) + assert.Equal(t, "some/image/path:"+v1alpha1.DefaultVersion, si) +} - cluster := &v1alpha1.Cluster{ - Spec: v1alpha1.ClusterSpec{ - Resources: &v1alpha1.Resources{ - Server: &mysqlServerResourceRequirements, - }, - }, - } +func TestClusterNoImage(t *testing.T) { + cluster := &v1alpha1.Cluster{} + cluster.EnsureDefaults() statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") - assert.Equal(t, mysqlServerResourceRequirements, statefulSet.Spec.Template.Spec.Containers[0].Resources, "MySQL-Server container resource requirements do not match expected.") - assert.Nil(t, statefulSet.Spec.Template.Spec.Containers[1].Resources.Limits, "MySQL-Agent container has resource limits set which were not initially defined in the spec") - assert.Nil(t, statefulSet.Spec.Template.Spec.Containers[1].Resources.Requests, "MySQL-Agent container has resource requests set which were not initially defined in the spec") + si := statefulSet.Spec.Template.Spec.Containers[0].Image + + assert.Equal(t, v1alpha1.MysqlServer+":"+v1alpha1.DefaultVersion, si) } From 83c4da0081e943e9364fc81584def5892e2ae0f4 Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Thu, 4 Oct 2018 11:02:26 +0100 Subject: [PATCH 5/8] Fixed rebase --- .../statefulsets/statefulset_test.go | 71 ++++++++++++++++++- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/pkg/resources/statefulsets/statefulset_test.go b/pkg/resources/statefulsets/statefulset_test.go index 960d8b0aa..699c3a04d 100644 --- a/pkg/resources/statefulsets/statefulset_test.go +++ b/pkg/resources/statefulsets/statefulset_test.go @@ -18,10 +18,9 @@ import ( "reflect" "testing" - "k8s.io/api/core/v1" - "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/oracle/mysql-operator/pkg/apis/mysql/v1alpha1" @@ -224,11 +223,77 @@ func TestClusterWithTolerations(t *testing.T) { } } +func TestClusterWithResourceRequirements(t *testing.T) { + mysqlServerResourceRequirements := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("2"), + corev1.ResourceMemory: resource.MustParse("2Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + } + + mysqlAgentResourceRequirements := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("100m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + } + + cluster := &v1alpha1.Cluster{ + Spec: v1alpha1.ClusterSpec{ + Resources: &v1alpha1.Resources{ + Server: &mysqlServerResourceRequirements, + Agent: &mysqlAgentResourceRequirements, + }, + }, + } + + statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") + + assert.Equal(t, mysqlServerResourceRequirements, statefulSet.Spec.Template.Spec.Containers[0].Resources, "MySQL-Server container resource requirements do not match expected.") + assert.Equal(t, mysqlAgentResourceRequirements, statefulSet.Spec.Template.Spec.Containers[1].Resources, "MySQL-Agent container resource requirements do not match expected.") +} + +func TestClusterWithOnlyMysqlServerResourceRequirements(t *testing.T) { + mysqlServerResourceRequirements := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("2"), + corev1.ResourceMemory: resource.MustParse("2Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + } + + cluster := &v1alpha1.Cluster{ + Spec: v1alpha1.ClusterSpec{ + Resources: &v1alpha1.Resources{ + Server: &mysqlServerResourceRequirements, + }, + }, + } + + statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") + + assert.Equal(t, mysqlServerResourceRequirements, statefulSet.Spec.Template.Spec.Containers[0].Resources, "MySQL-Server container resource requirements do not match expected.") + assert.Nil(t, statefulSet.Spec.Template.Spec.Containers[1].Resources.Limits, "MySQL-Agent container has resource limits set which were not initially defined in the spec") + assert.Nil(t, statefulSet.Spec.Template.Spec.Containers[1].Resources.Requests, "MySQL-Agent container has resource requests set which were not initially defined in the spec") + +} + func TestClusterEnterpriseImage(t *testing.T) { cluster := &v1alpha1.Cluster{ Spec: v1alpha1.ClusterSpec{ MySQLServerImage: "some/image/path", - ImagePullSecret: &v1.LocalObjectReference{ + ImagePullSecret: &corev1.LocalObjectReference{ Name: "someSecretName", }, }, From e8328a6ebdebc1b3bc511c0ee16548852f596925 Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Thu, 4 Oct 2018 13:04:04 +0100 Subject: [PATCH 6/8] Allow MySQL server image default to be specified in operator config --- docs/enterprise-edition-example.md | 27 ++++++++------- .../cluster/cluster-enterprise-version.yaml | 9 +++-- pkg/apis/mysql/v1alpha1/helpers.go | 8 ++--- pkg/apis/mysql/v1alpha1/types.go | 8 ++--- pkg/options/operator/options.go | 13 ++++++-- pkg/resources/statefulsets/statefulset.go | 13 ++++++-- .../statefulsets/statefulset_test.go | 33 +++++++++++++++++-- 7 files changed, 73 insertions(+), 38 deletions(-) diff --git a/docs/enterprise-edition-example.md b/docs/enterprise-edition-example.md index c7d2020f8..ae0e7dfb0 100644 --- a/docs/enterprise-edition-example.md +++ b/docs/enterprise-edition-example.md @@ -1,10 +1,10 @@ # Enterprise edition tutorial -This tutorial will explain how to create a mysqlcluster that runs the enterprise version of mysql. +This tutorial will explain how to create a MySQL cluster that runs the enterprise version of MySQL. ## Prerequisites -- The mysql-operator repository checked out locally. -- Access to a Docker registry that contains the enterprise version of mysql. +- The MySQL operator repository checked out locally. +- Access to a Docker registry that contains the enterprise version of MySQL. ## 01 - Create the Operator You will need to create the following: @@ -14,18 +14,17 @@ You will need to create the following: 3. The Operator 4. The Agent ServiceAccount & RoleBinding -The creation of these resources can be achieved by following the [introductory tutorial][1]; return here before creating a MySQL Cluster. +The creation of these resources can be achieved by following the [introductory tutorial][1]; return here before creating a MySQL cluster. ## 02 - Create a secret with registry credentials -To be able to pull the mysql enterprise edition from docker it is necessary to provide credentials, these credentials must be supplied in the form of a Kubernetes secret. +To be able to pull the MySQL Enterprise Edition from Docker it is necessary to provide credentials, these credentials must be supplied in the form of a Kubernetes secret. -- The name of the secret `myregistrykey` must match the name in the `imagepullsecrets` which we will specify in the cluster config in step 03. -- The secret must be created in the same namespace as the MySQL Cluster which we will make in step 03. It must also be in the same namespace as the RBAC permissions created in step 01. -- If you are pulling the mysql enterprise image from a different registry then the secret must contain the relevant credentials for that registry. +- Remember the name of the secret *myregistrykey* as this will need to be used in step 03 when creating the cluster. +- If you are pulling the MySQL Enterprise image from a different registry than the one in the example then the secret must contain the relevant credentials for that registry. ->For alternative ways to create Kubernetes secretes see their documentation on [creating secrets from docker configs](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) or [creating secrets manually](https://kubernetes.io/docs/concepts/containers/images/#creating-a-secret-with-a-docker-config). +>For alternative ways to create Kubernetes secrets see their documentation on [creating secrets from Docker configs](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) or [creating secrets manually](https://kubernetes.io/docs/concepts/containers/images/#creating-a-secret-with-a-docker-config). -Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. add the `-n` flag to specify a namespace if you do not want to use the default namespace. +Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. Add the `-n` flag to specify a namespace if you do not want to use the default namespace. ``` kubectl create secret docker-registry myregistrykey \ --docker-server=https://index.docker.io/v1/ \ @@ -36,10 +35,10 @@ kubectl create secret docker-registry myregistrykey \ ## 03 - Create your MySQL Cluster Finally, create your MySQL Cluster with the required specifications entered under `spec:` -- The mysqlServer field should be the path to a registry containing the enterprise edition of MySQL. -- The imagePullSecret: name: Should be the name of a Kubernetes secret in the same namespace that contains your credentials for the docker registry. -- The version to be used must be specified, without this, a default version is used which is **not** guaranteed to match an available image of MySQL Enterprise. -- The namespace of the cluster must match the namespace of the secret we created in step 02. +- The `repository:` field should be the path to a Docker registry containing the enterprise edition of MySQL. If this is ommited, the default is taken from the MySQL operator field `defaultMysqlServer:` which you can also specify. +- The `imagePullSecrets`: field allows you to specify a list of Kubernetes secret names. These secret(s) should contains your credentials for the Docker registry. +- The version to be used should be specified, without this, a default version is used which is **not** guaranteed to match an available image of MySQL Enterprise. +- The namespace of the cluster must match the namespace of the RBAC permissions created in step 01. ``` kubectl apply -f examples/cluster/cluster-enterprise-version.yaml ``` diff --git a/examples/cluster/cluster-enterprise-version.yaml b/examples/cluster/cluster-enterprise-version.yaml index ee003d3e8..0db356241 100644 --- a/examples/cluster/cluster-enterprise-version.yaml +++ b/examples/cluster/cluster-enterprise-version.yaml @@ -1,10 +1,9 @@ apiVersion: mysql.oracle.com/v1alpha1 kind: Cluster metadata: - name: mysql - namespace: default + name: mysql-enterprise spec: version: "8.0.11" - mysqlServer: store/oracle/mysql-enterprise-server - imagePullSecret: - name: myregistrykey + repository: store/oracle/mysql-enterprise-server + imagePullSecrets: + - name: myregistrykey diff --git a/pkg/apis/mysql/v1alpha1/helpers.go b/pkg/apis/mysql/v1alpha1/helpers.go index f68f0b7e8..42eee4870 100644 --- a/pkg/apis/mysql/v1alpha1/helpers.go +++ b/pkg/apis/mysql/v1alpha1/helpers.go @@ -54,8 +54,8 @@ func getOperatorVersionLabel(labelMap map[string]string) string { // EnsureDefaults will ensure that if a user omits any fields in the // spec that are required, we set some sensible defaults. -// For example a user can choose to omit the version -// and number of members. +// For example a user can choose to omit the version and number of +// members. MySQL server image default is defined through operator spec. func (c *Cluster) EnsureDefaults() *Cluster { if c.Spec.Members == 0 { c.Spec.Members = defaultMembers @@ -69,10 +69,6 @@ func (c *Cluster) EnsureDefaults() *Cluster { c.Spec.Version = DefaultVersion } - if c.Spec.MySQLServerImage == "" { - c.Spec.MySQLServerImage = MysqlServer - } - return c } diff --git a/pkg/apis/mysql/v1alpha1/types.go b/pkg/apis/mysql/v1alpha1/types.go index cd09a4404..d4e2305c0 100644 --- a/pkg/apis/mysql/v1alpha1/types.go +++ b/pkg/apis/mysql/v1alpha1/types.go @@ -28,11 +28,11 @@ const MinimumMySQLVersion = "8.0.11" type ClusterSpec struct { // Version defines the MySQL Docker image version. Version string `json:"version"` - // MySQLServerImage defines the image to be pulled for the mysqlServer. - MySQLServerImage string `json:"mysqlServer"` + // Repository defines the image to be pulled for the MySQL server. + Repository string `json:"repository"` // ImagePullSecret defines the name of the secret that contains the - // required credentials for pulling the MySQLServerImage. - ImagePullSecret *v1.LocalObjectReference `json:"imagePullSecret"` + // required credentials for pulling from the specified Repository. + ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecret"` // Members defines the number of MySQL instances in a cluster Members int32 `json:"members,omitempty"` // BaseServerID defines the base number used to create unique server_id diff --git a/pkg/options/operator/options.go b/pkg/options/operator/options.go index e7cfd43c1..722710b4d 100644 --- a/pkg/options/operator/options.go +++ b/pkg/options/operator/options.go @@ -29,13 +29,16 @@ import ( ) const ( - mysqlAgent = "iad.ocir.io/oracle/mysql-agent" + mysqlAgent = "iad.ocir.io/oracle/mysql-agent" + mysqlServer = "mysql/mysql-server" ) // Images is the configuration of required MySQLOperator images. Remember to configure the appropriate -// credentials for the target repositories. Image for mysqlServer is specified in ClusterSpec +// credentials for the target repositories. The DefaultMySQLServerImage can be overridden on a per-cluster +// basis by setting the Repository field. type Images struct { - MySQLAgentImage string `yaml:"mysqlAgent"` + MySQLAgentImage string `yaml:"mysqlAgent"` + DefaultMySQLServerImage string `yaml:"defaultMysqlServer"` } // MySQLOperatorOpts holds the options for the MySQLOperator. @@ -107,6 +110,9 @@ func (s *MySQLOperatorOpts) EnsureDefaults() { if s.Images.MySQLAgentImage == "" { s.Images.MySQLAgentImage = mysqlAgent } + if s.Images.DefaultMySQLServerImage == "" { + s.Images.DefaultMySQLServerImage = mysqlServer + } if s.MinResyncPeriod.Duration <= 0 { s.MinResyncPeriod = metav1.Duration{Duration: 12 * time.Hour} } @@ -117,6 +123,7 @@ func (s *MySQLOperatorOpts) AddFlags(fs *pflag.FlagSet) *pflag.FlagSet { fs.StringVar(&s.KubeConfig, "kubeconfig", s.KubeConfig, "Path to Kubeconfig file with authorization and master location information.") fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig).") fs.StringVar(&s.Namespace, "namespace", metav1.NamespaceAll, "The namespace for which the MySQL operator manages MySQL clusters. Defaults to all.") + fs.StringVar(&s.Images.DefaultMySQLServerImage, "mysql-server-image", mysqlServer, "The name of the default target for the 'mysql-server' image (can be overridden on a per-cluster basis). Defaults to: "+mysqlServer+".") fs.StringVar(&s.Images.MySQLAgentImage, "mysql-agent-image", s.Images.MySQLAgentImage, "The name of the target 'mysql-agent' image. Defaults to: iad.ocir.io/oracle/mysql-agent.") fs.DurationVar(&s.MinResyncPeriod.Duration, "min-resync-period", s.MinResyncPeriod.Duration, "The resync period in reflectors will be random between MinResyncPeriod and 2*MinResyncPeriod.") return fs diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index 1eb4cb8fc..893565b4d 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -344,8 +344,15 @@ func NewForCluster(cluster *v1alpha1.Cluster, images operatoropts.Images, servic }) } + var serverImage string + if cluster.Spec.Repository != "" { + serverImage = cluster.Spec.Repository + } else { + serverImage = images.DefaultMySQLServerImage + } + containers := []v1.Container{ - mysqlServerContainer(cluster, cluster.Spec.MySQLServerImage, rootPassword, members, baseServerID), + mysqlServerContainer(cluster, serverImage, rootPassword, members, baseServerID), mysqlAgentContainer(cluster, images.MySQLAgentImage, rootPassword, members)} podLabels := map[string]string{ @@ -399,8 +406,8 @@ func NewForCluster(cluster *v1alpha1.Cluster, images operatoropts.Images, servic }, } - if cluster.Spec.ImagePullSecret != nil { - ss.Spec.Template.Spec.ImagePullSecrets = append(ss.Spec.Template.Spec.ImagePullSecrets, *cluster.Spec.ImagePullSecret) + if cluster.Spec.ImagePullSecrets != nil { + ss.Spec.Template.Spec.ImagePullSecrets = append(ss.Spec.Template.Spec.ImagePullSecrets, cluster.Spec.ImagePullSecrets...) } if cluster.Spec.VolumeClaimTemplate != nil { ss.Spec.VolumeClaimTemplates = append(ss.Spec.VolumeClaimTemplates, *cluster.Spec.VolumeClaimTemplate) diff --git a/pkg/resources/statefulsets/statefulset_test.go b/pkg/resources/statefulsets/statefulset_test.go index 699c3a04d..9f1cf8eac 100644 --- a/pkg/resources/statefulsets/statefulset_test.go +++ b/pkg/resources/statefulsets/statefulset_test.go @@ -292,10 +292,10 @@ func TestClusterWithOnlyMysqlServerResourceRequirements(t *testing.T) { func TestClusterEnterpriseImage(t *testing.T) { cluster := &v1alpha1.Cluster{ Spec: v1alpha1.ClusterSpec{ - MySQLServerImage: "some/image/path", - ImagePullSecret: &corev1.LocalObjectReference{ + Repository: "some/image/path", + ImagePullSecrets: []corev1.LocalObjectReference{{ Name: "someSecretName", - }, + }}, }, } cluster.EnsureDefaults() @@ -320,3 +320,30 @@ func TestClusterNoImage(t *testing.T) { assert.Equal(t, v1alpha1.MysqlServer+":"+v1alpha1.DefaultVersion, si) } + +func TestClusterNoImageOperatorDefault(t *testing.T) { + cluster := &v1alpha1.Cluster{} + cluster.EnsureDefaults() + + operatorConf := mockOperatorConfig() + operatorConf.Images.DefaultMySQLServerImage = "newDefaultImage" + statefulSet := NewForCluster(cluster, operatorConf.Images, "mycluster") + + si := statefulSet.Spec.Template.Spec.Containers[0].Image + + assert.Equal(t, "newDefaultImage:"+v1alpha1.DefaultVersion, si) +} + +func TestClusterDefaultOverride(t *testing.T) { + cluster := &v1alpha1.Cluster{} + cluster.EnsureDefaults() + cluster.Spec.Repository = "OverrideDefaultImage" + + operatorConf := mockOperatorConfig() + operatorConf.Images.DefaultMySQLServerImage = "newDefaultImage" + statefulSet := NewForCluster(cluster, operatorConf.Images, "mycluster") + + si := statefulSet.Spec.Template.Spec.Containers[0].Image + + assert.Equal(t, "OverrideDefaultImage:"+v1alpha1.DefaultVersion, si) +} From eb5daf6bde23610790154edf12a82f9f3eaa6239 Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Thu, 4 Oct 2018 14:02:53 +0100 Subject: [PATCH 7/8] Fixed formating and test --- docs/enterprise-edition-example.md | 10 +++++----- pkg/options/operator/options_test.go | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/enterprise-edition-example.md b/docs/enterprise-edition-example.md index ae0e7dfb0..514d24807 100644 --- a/docs/enterprise-edition-example.md +++ b/docs/enterprise-edition-example.md @@ -24,7 +24,7 @@ To be able to pull the MySQL Enterprise Edition from Docker it is necessary to p >For alternative ways to create Kubernetes secrets see their documentation on [creating secrets from Docker configs](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) or [creating secrets manually](https://kubernetes.io/docs/concepts/containers/images/#creating-a-secret-with-a-docker-config). -Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. Add the `-n` flag to specify a namespace if you do not want to use the default namespace. +Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. ``` kubectl create secret docker-registry myregistrykey \ --docker-server=https://index.docker.io/v1/ \ @@ -35,19 +35,19 @@ kubectl create secret docker-registry myregistrykey \ ## 03 - Create your MySQL Cluster Finally, create your MySQL Cluster with the required specifications entered under `spec:` -- The `repository:` field should be the path to a Docker registry containing the enterprise edition of MySQL. If this is ommited, the default is taken from the MySQL operator field `defaultMysqlServer:` which you can also specify. -- The `imagePullSecrets`: field allows you to specify a list of Kubernetes secret names. These secret(s) should contains your credentials for the Docker registry. +- The `repository:` field should be the path to a Docker registry containing the enterprise edition of MySQL. If this is omitted, the default is taken from the MySQL operator field `defaultMysqlServer:` which you can also specify. +- The `imagePullSecrets`: field allows you to specify a list of Kubernetes secret names. These secret(s) should contain your credentials for the Docker registry. - The version to be used should be specified, without this, a default version is used which is **not** guaranteed to match an available image of MySQL Enterprise. - The namespace of the cluster must match the namespace of the RBAC permissions created in step 01. ``` kubectl apply -f examples/cluster/cluster-enterprise-version.yaml ``` ### Check that it is running -You can now run the following command to access the sql prompt in your MySQL Cluster, just replace `` with the namespace you created your cluster in. +You can now run the following command to access the SQL prompt in your MySQL Cluster, just replace `` with the namespace you created your cluster in. ``` sh hack/mysql.sh /mysql-0 ``` >*If you run into issues when creating RBAC roles see [Access controls](https://docs.cloud.oracle.com/iaas/Content/ContEng/Concepts/contengabouta]ccesscontrol.htm?) for more information. -[1]: docs/tutorial.md \ No newline at end of file +[1]: docs/tutorial.md diff --git a/pkg/options/operator/options_test.go b/pkg/options/operator/options_test.go index a9c77b676..b3eb1f643 100644 --- a/pkg/options/operator/options_test.go +++ b/pkg/options/operator/options_test.go @@ -63,7 +63,8 @@ func mockMySQLOperatorOpts() MySQLOperatorOpts { Master: "some-master", Hostname: "some-hostname", Images: Images{ - MySQLAgentImage: "some-agent-img", + MySQLAgentImage: "some-agent-img", + DefaultMySQLServerImage: "mysql/mysql-server", }, MinResyncPeriod: v1.Duration{Duration: 42}, } From eefb0cccb10c2721fc3dd996d4ec8f3fdd2b0f7b Mon Sep 17 00:00:00 2001 From: bcurrerb Date: Thu, 4 Oct 2018 14:02:53 +0100 Subject: [PATCH 8/8] Fixed test and defaulting --- docs/enterprise-edition-example.md | 10 ++++---- pkg/apis/mysql/v1alpha1/helpers.go | 2 +- pkg/apis/mysql/v1alpha1/types.go | 5 ++-- pkg/controllers/cluster/controller.go | 4 ++++ pkg/options/operator/options.go | 9 +++---- pkg/options/operator/options_test.go | 3 ++- pkg/resources/statefulsets/statefulset.go | 9 +------ .../statefulsets/statefulset_test.go | 24 ------------------- 8 files changed, 20 insertions(+), 46 deletions(-) diff --git a/docs/enterprise-edition-example.md b/docs/enterprise-edition-example.md index ae0e7dfb0..514d24807 100644 --- a/docs/enterprise-edition-example.md +++ b/docs/enterprise-edition-example.md @@ -24,7 +24,7 @@ To be able to pull the MySQL Enterprise Edition from Docker it is necessary to p >For alternative ways to create Kubernetes secrets see their documentation on [creating secrets from Docker configs](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) or [creating secrets manually](https://kubernetes.io/docs/concepts/containers/images/#creating-a-secret-with-a-docker-config). -Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. Add the `-n` flag to specify a namespace if you do not want to use the default namespace. +Enter your credentials into the following command and execute it to create a Kubernetes secret that will enable pulling images from the Docker store. ``` kubectl create secret docker-registry myregistrykey \ --docker-server=https://index.docker.io/v1/ \ @@ -35,19 +35,19 @@ kubectl create secret docker-registry myregistrykey \ ## 03 - Create your MySQL Cluster Finally, create your MySQL Cluster with the required specifications entered under `spec:` -- The `repository:` field should be the path to a Docker registry containing the enterprise edition of MySQL. If this is ommited, the default is taken from the MySQL operator field `defaultMysqlServer:` which you can also specify. -- The `imagePullSecrets`: field allows you to specify a list of Kubernetes secret names. These secret(s) should contains your credentials for the Docker registry. +- The `repository:` field should be the path to a Docker registry containing the enterprise edition of MySQL. If this is omitted, the default is taken from the MySQL operator field `defaultMysqlServer:` which you can also specify. +- The `imagePullSecrets`: field allows you to specify a list of Kubernetes secret names. These secret(s) should contain your credentials for the Docker registry. - The version to be used should be specified, without this, a default version is used which is **not** guaranteed to match an available image of MySQL Enterprise. - The namespace of the cluster must match the namespace of the RBAC permissions created in step 01. ``` kubectl apply -f examples/cluster/cluster-enterprise-version.yaml ``` ### Check that it is running -You can now run the following command to access the sql prompt in your MySQL Cluster, just replace `` with the namespace you created your cluster in. +You can now run the following command to access the SQL prompt in your MySQL Cluster, just replace `` with the namespace you created your cluster in. ``` sh hack/mysql.sh /mysql-0 ``` >*If you run into issues when creating RBAC roles see [Access controls](https://docs.cloud.oracle.com/iaas/Content/ContEng/Concepts/contengabouta]ccesscontrol.htm?) for more information. -[1]: docs/tutorial.md \ No newline at end of file +[1]: docs/tutorial.md diff --git a/pkg/apis/mysql/v1alpha1/helpers.go b/pkg/apis/mysql/v1alpha1/helpers.go index 42eee4870..df25b1465 100644 --- a/pkg/apis/mysql/v1alpha1/helpers.go +++ b/pkg/apis/mysql/v1alpha1/helpers.go @@ -55,7 +55,7 @@ func getOperatorVersionLabel(labelMap map[string]string) string { // EnsureDefaults will ensure that if a user omits any fields in the // spec that are required, we set some sensible defaults. // For example a user can choose to omit the version and number of -// members. MySQL server image default is defined through operator spec. +// members. func (c *Cluster) EnsureDefaults() *Cluster { if c.Spec.Members == 0 { c.Spec.Members = defaultMembers diff --git a/pkg/apis/mysql/v1alpha1/types.go b/pkg/apis/mysql/v1alpha1/types.go index d4e2305c0..dcc8735cf 100644 --- a/pkg/apis/mysql/v1alpha1/types.go +++ b/pkg/apis/mysql/v1alpha1/types.go @@ -15,7 +15,6 @@ package v1alpha1 import ( - "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,11 +27,11 @@ const MinimumMySQLVersion = "8.0.11" type ClusterSpec struct { // Version defines the MySQL Docker image version. Version string `json:"version"` - // Repository defines the image to be pulled for the MySQL server. + // Repository defines the image repository from which to pull the MySQL server image. Repository string `json:"repository"` // ImagePullSecret defines the name of the secret that contains the // required credentials for pulling from the specified Repository. - ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecret"` + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecret"` // Members defines the number of MySQL instances in a cluster Members int32 `json:"members,omitempty"` // BaseServerID defines the base number used to create unique server_id diff --git a/pkg/controllers/cluster/controller.go b/pkg/controllers/cluster/controller.go index 9db425ffb..7d4eb874c 100644 --- a/pkg/controllers/cluster/controller.go +++ b/pkg/controllers/cluster/controller.go @@ -324,6 +324,10 @@ func (m *MySQLController) syncHandler(key string) error { return errors.Wrap(err, "validating Cluster") } + if cluster.Spec.Repository == "" { + cluster.Spec.Repository = m.opConfig.Images.DefaultMySQLServerImage + } + operatorVersion := buildversion.GetBuildVersion() // Ensure that the required labels are set on the cluster. sel := combineSelectors(SelectorForCluster(cluster), SelectorForClusterOperatorVersion(operatorVersion)) diff --git a/pkg/options/operator/options.go b/pkg/options/operator/options.go index 722710b4d..504d14f3a 100644 --- a/pkg/options/operator/options.go +++ b/pkg/options/operator/options.go @@ -15,12 +15,14 @@ package operator import ( + "fmt" "io/ioutil" "os" "path/filepath" "time" "github.com/golang/glog" + "github.com/oracle/mysql-operator/pkg/apis/mysql/v1alpha1" "github.com/pkg/errors" "github.com/spf13/pflag" "gopkg.in/yaml.v2" @@ -29,8 +31,7 @@ import ( ) const ( - mysqlAgent = "iad.ocir.io/oracle/mysql-agent" - mysqlServer = "mysql/mysql-server" + mysqlAgent = "iad.ocir.io/oracle/mysql-agent" ) // Images is the configuration of required MySQLOperator images. Remember to configure the appropriate @@ -111,7 +112,7 @@ func (s *MySQLOperatorOpts) EnsureDefaults() { s.Images.MySQLAgentImage = mysqlAgent } if s.Images.DefaultMySQLServerImage == "" { - s.Images.DefaultMySQLServerImage = mysqlServer + s.Images.DefaultMySQLServerImage = v1alpha1.MysqlServer } if s.MinResyncPeriod.Duration <= 0 { s.MinResyncPeriod = metav1.Duration{Duration: 12 * time.Hour} @@ -123,7 +124,7 @@ func (s *MySQLOperatorOpts) AddFlags(fs *pflag.FlagSet) *pflag.FlagSet { fs.StringVar(&s.KubeConfig, "kubeconfig", s.KubeConfig, "Path to Kubeconfig file with authorization and master location information.") fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig).") fs.StringVar(&s.Namespace, "namespace", metav1.NamespaceAll, "The namespace for which the MySQL operator manages MySQL clusters. Defaults to all.") - fs.StringVar(&s.Images.DefaultMySQLServerImage, "mysql-server-image", mysqlServer, "The name of the default target for the 'mysql-server' image (can be overridden on a per-cluster basis). Defaults to: "+mysqlServer+".") + fs.StringVar(&s.Images.DefaultMySQLServerImage, "mysql-server-image", s.Images.DefaultMySQLServerImage, fmt.Sprintf("The default image repository to pull the MySQL Server image from (can be overridden on a per-cluster basis). Defaults to: %q.", v1alpha1.MysqlServer)) fs.StringVar(&s.Images.MySQLAgentImage, "mysql-agent-image", s.Images.MySQLAgentImage, "The name of the target 'mysql-agent' image. Defaults to: iad.ocir.io/oracle/mysql-agent.") fs.DurationVar(&s.MinResyncPeriod.Duration, "min-resync-period", s.MinResyncPeriod.Duration, "The resync period in reflectors will be random between MinResyncPeriod and 2*MinResyncPeriod.") return fs diff --git a/pkg/options/operator/options_test.go b/pkg/options/operator/options_test.go index a9c77b676..b3eb1f643 100644 --- a/pkg/options/operator/options_test.go +++ b/pkg/options/operator/options_test.go @@ -63,7 +63,8 @@ func mockMySQLOperatorOpts() MySQLOperatorOpts { Master: "some-master", Hostname: "some-hostname", Images: Images{ - MySQLAgentImage: "some-agent-img", + MySQLAgentImage: "some-agent-img", + DefaultMySQLServerImage: "mysql/mysql-server", }, MinResyncPeriod: v1.Duration{Duration: 42}, } diff --git a/pkg/resources/statefulsets/statefulset.go b/pkg/resources/statefulsets/statefulset.go index 893565b4d..ebfea7a10 100644 --- a/pkg/resources/statefulsets/statefulset.go +++ b/pkg/resources/statefulsets/statefulset.go @@ -344,15 +344,8 @@ func NewForCluster(cluster *v1alpha1.Cluster, images operatoropts.Images, servic }) } - var serverImage string - if cluster.Spec.Repository != "" { - serverImage = cluster.Spec.Repository - } else { - serverImage = images.DefaultMySQLServerImage - } - containers := []v1.Container{ - mysqlServerContainer(cluster, serverImage, rootPassword, members, baseServerID), + mysqlServerContainer(cluster, cluster.Spec.Repository, rootPassword, members, baseServerID), mysqlAgentContainer(cluster, images.MySQLAgentImage, rootPassword, members)} podLabels := map[string]string{ diff --git a/pkg/resources/statefulsets/statefulset_test.go b/pkg/resources/statefulsets/statefulset_test.go index 9f1cf8eac..7d8544c05 100644 --- a/pkg/resources/statefulsets/statefulset_test.go +++ b/pkg/resources/statefulsets/statefulset_test.go @@ -310,30 +310,6 @@ func TestClusterEnterpriseImage(t *testing.T) { assert.Equal(t, "some/image/path:"+v1alpha1.DefaultVersion, si) } -func TestClusterNoImage(t *testing.T) { - cluster := &v1alpha1.Cluster{} - cluster.EnsureDefaults() - - statefulSet := NewForCluster(cluster, mockOperatorConfig().Images, "mycluster") - - si := statefulSet.Spec.Template.Spec.Containers[0].Image - - assert.Equal(t, v1alpha1.MysqlServer+":"+v1alpha1.DefaultVersion, si) -} - -func TestClusterNoImageOperatorDefault(t *testing.T) { - cluster := &v1alpha1.Cluster{} - cluster.EnsureDefaults() - - operatorConf := mockOperatorConfig() - operatorConf.Images.DefaultMySQLServerImage = "newDefaultImage" - statefulSet := NewForCluster(cluster, operatorConf.Images, "mycluster") - - si := statefulSet.Spec.Template.Spec.Containers[0].Image - - assert.Equal(t, "newDefaultImage:"+v1alpha1.DefaultVersion, si) -} - func TestClusterDefaultOverride(t *testing.T) { cluster := &v1alpha1.Cluster{} cluster.EnsureDefaults()