diff --git a/examples/patch.yaml b/examples/patch.yaml index 70454a61e92..ef2a7f1d517 100644 --- a/examples/patch.yaml +++ b/examples/patch.yaml @@ -4,9 +4,9 @@ metadata: name: minio spec: zones: - - name: "zone-0" - ## Number of MinIO servers/pods in zone-0. + - volumesPerServer: 4 + ## Number of MinIO servers/pods in zone 0. servers: 4 - - name: "zone-1" - ## Number of MinIO servers/pods in zone-1. + - volumesPerServer: 4 + ## Number of MinIO servers/pods in zone 1. servers: 4 diff --git a/examples/tenant-mcs.yaml b/examples/tenant-console.yaml similarity index 81% rename from examples/tenant-mcs.yaml rename to examples/tenant-console.yaml index eebafa5e5f2..9019018e45f 100644 --- a/examples/tenant-mcs.yaml +++ b/examples/tenant-console.yaml @@ -60,31 +60,30 @@ spec: credsSecret: name: minio-creds-secret zones: - - name: "zone-0" + - volumesPerServer: 4 ## Number of MinIO servers/pods in this zone. ## For standalone mode, supply 1. For distributed mode, supply 4 or more. ## Note that the operator does not support upgrading from standalone to distributed mode. servers: 4 - ## Supply number of volumes to be mounted per MinIO server instance. - volumesPerServer: 4 + ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. + ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may + ## lead to unbound PVCs and missing data + volumeClaimTemplate: + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Ti ## Mount path where PV will be mounted inside container(s). Defaults to "/export". mountPath: /export ## Sub path inside Mount path where MinIO starts. Defaults to "". # subPath: /data - ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. - ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may - ## lead to unbound PVCs and missing data - volumeClaimTemplate: - metadata: - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Ti + ## Define configuration for MCS (Graphical user interface for MinIO) - mcs: + console: image: minio/mcs:v0.2.0 replicas: 2 mcsSecret: @@ -110,22 +109,22 @@ spec: commonName: "" organizationName: [] dnsNames: [] - ## Used to specify a toleration for a pod - # tolerations: - # - effect: NoSchedule - # key: dedicated - # operator: Equal - # value: storage - ## Add environment variables to be set in MinIO container (https://github.com/minio/minio/tree/master/docs/config) - # env: - # - name: MINIO_BROWSER - # value: "off" # to turn-off browser - # - name: MINIO_STORAGE_CLASS_STANDARD - # value: "EC:4" - ## Configure resource requests and limits for MinIO containers - # resources: + ## Used to specify a toleration for a pod + # tolerations: + # - effect: NoSchedule + # key: dedicated + # operator: Equal + # value: storage + ## Add environment variables to be set in MinIO container (https://github.com/minio/minio/tree/master/docs/config) + # env: + # - name: MINIO_BROWSER + # value: "off" # to turn-off browser + # - name: MINIO_STORAGE_CLASS_STANDARD + # value: "EC:4" + ## Configure resource requests and limits for MinIO containers + # resources: # requests: - # memory: 20Gi + # memory: 20Gi ## Liveness probe detects situations where MinIO server instance ## is not working properly and needs restart. Kubernetes automatically ## restarts the pods if liveness checks fail. diff --git a/examples/tenant-kes.yaml b/examples/tenant-kes.yaml index aadf9d12add..174b6a3aa21 100644 --- a/examples/tenant-kes.yaml +++ b/examples/tenant-kes.yaml @@ -60,31 +60,31 @@ spec: credsSecret: name: minio-creds-secret zones: - - name: "zone-0" + - volumesPerServer: 4 ## Number of MinIO servers/pods in this zone. ## For standalone mode, supply 1. For distributed mode, supply 4 or more. ## Note that the operator does not support upgrading from standalone to distributed mode. servers: 4 - ## Supply number of volumes to be mounted per MinIO server instance. - volumesPerServer: 4 + ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. + ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may + ## lead to unbound PVCs and missing data + volumeClaimTemplate: + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Ti + ## Mount path where PV will be mounted inside container(s). Defaults to "/export". mountPath: /export ## Sub path inside Mount path where MinIO starts. Defaults to "". # subPath: /data - ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. - ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may - ## lead to unbound PVCs and missing data - volumeClaimTemplate: - metadata: - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Ti + ## Define configuration for MCS (Graphical user interface for MinIO) - mcs: + console: image: minio/mcs:v0.2.0 replicas: 2 mcsSecret: @@ -123,22 +123,22 @@ spec: commonName: "" organizationName: [] dnsNames: [] - ## Used to specify a toleration for a pod - # tolerations: - # - effect: NoSchedule - # key: dedicated - # operator: Equal - # value: storage - ## Add environment variables to be set in MinIO container (https://github.com/minio/minio/tree/master/docs/config) - # env: - # - name: MINIO_BROWSER - # value: "off" # to turn-off browser - # - name: MINIO_STORAGE_CLASS_STANDARD - # value: "EC:4" - ## Configure resource requests and limits for MinIO containers - # resources: + ## Used to specify a toleration for a pod + # tolerations: + # - effect: NoSchedule + # key: dedicated + # operator: Equal + # value: storage + ## Add environment variables to be set in MinIO container (https://github.com/minio/minio/tree/master/docs/config) + # env: + # - name: MINIO_BROWSER + # value: "off" # to turn-off browser + # - name: MINIO_STORAGE_CLASS_STANDARD + # value: "EC:4" + ## Configure resource requests and limits for MinIO containers + # resources: # requests: - # memory: 20Gi + # memory: 20Gi ## Liveness probe detects situations where MinIO server instance ## is not working properly and needs restart. Kubernetes automatically ## restarts the pods if liveness checks fail. diff --git a/examples/tenant-pod-security-policy.yaml b/examples/tenant-pod-security-policy.yaml index d33a83d57da..58d3ed89460 100644 --- a/examples/tenant-pod-security-policy.yaml +++ b/examples/tenant-pod-security-policy.yaml @@ -63,7 +63,7 @@ rules: - "minio-pods-policy" --- kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 metadata: name: minio-pods-binding roleRef: @@ -100,29 +100,27 @@ spec: ## Service account to be used for all the MinIO Pods serviceAccountName: minio-pods zones: - - name: "zone-0" + - volumesPerServer: 4 ## Number of MinIO servers/pods in this zone. ## For standalone mode, supply 1. For distributed mode, supply 4 or more. ## Note that the operator does not support upgrading from standalone to distributed mode. servers: 4 - ## Supply number of volumes to be mounted per MinIO server instance. - volumesPerServer: 4 + ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. + ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may + ## lead to unbound PVCs and missing data + volumeClaimTemplate: + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Ti ## Mount path where PV will be mounted inside container(s). Defaults to "/export". mountPath: /export ## Sub path inside Mount path where MinIO starts. Defaults to "". # subPath: /data - ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. - ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may - ## lead to unbound PVCs and missing data - volumeClaimTemplate: - metadata: - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Ti ## Secret with credentials to be used by MinIO instance. credsSecret: name: minio-creds-secret diff --git a/examples/tenant.yaml b/examples/tenant.yaml index e1a04a77808..533435a0b96 100644 --- a/examples/tenant.yaml +++ b/examples/tenant.yaml @@ -46,13 +46,17 @@ spec: ## A ClusterIP Service will be created with the given name serviceName: minio-internal-service zones: - - name: "zone-0" - ## Number of MinIO servers/pods in this zone. - ## For standalone mode, supply 1. For distributed mode, supply 4 or more. - ## Note that the operator does not support upgrading from standalone to distributed mode. - servers: 4 - ## Supply number of volumes to be mounted per MinIO server instance. - volumesPerServer: 4 + - servers: 4 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Ti ## Mount path where PV will be mounted inside container(s). Defaults to "/export". mountPath: /export ## Sub path inside Mount path where MinIO starts. Defaults to "". @@ -60,15 +64,6 @@ spec: ## This VolumeClaimTemplate is used across all the volumes provisioned for MinIO cluster. ## Please do not change the volumeClaimTemplate field while expanding the cluster, this may ## lead to unbound PVCs and missing data - volumeClaimTemplate: - metadata: - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Ti ## Secret with credentials to be used by MinIO instance. credsSecret: name: minio-creds-secret @@ -90,22 +85,22 @@ spec: commonName: "" organizationName: [] dnsNames: [] - ## Used to specify a toleration for a pod - # tolerations: - # - effect: NoSchedule - # key: dedicated - # operator: Equal - # value: storage - ## Add environment variables to be set in MinIO container (https://github.com/minio/minio/tree/master/docs/config) - # env: - # - name: MINIO_BROWSER - # value: "off" # to turn-off browser - # - name: MINIO_STORAGE_CLASS_STANDARD - # value: "EC:2" - ## Configure resource requests and limits for MinIO containers - # resources: - # requests: - # memory: 20Gi + ## Used to specify a toleration for a pod + # tolerations: + # - effect: NoSchedule + # key: dedicated + # operator: Equal + # value: storage + ## Add environment variables to be set in MinIO container (https://github.com/minio/minio/tree/master/docs/config) + # env: + # - name: MINIO_BROWSER + # value: "off" # to turn-off browser + # - name: MINIO_STORAGE_CLASS_STANDARD + # value: "EC:2" + ## Configure resource requests and limits for MinIO containers + # resources: + # requests: + # memory: 20Gi ## Liveness probe detects situations where MinIO server instance ## is not working properly and needs restart. Kubernetes automatically ## restarts the pods if liveness checks fail. diff --git a/go.mod b/go.mod index 739810df65d..860ceec89d9 100644 --- a/go.mod +++ b/go.mod @@ -12,5 +12,6 @@ require ( k8s.io/api v0.18.0 k8s.io/apimachinery v0.18.0 k8s.io/client-go v0.18.0 + k8s.io/code-generator v0.18.6 // indirect k8s.io/klog v1.0.0 ) diff --git a/go.sum b/go.sum index 918b5b9b790..42ba4061f7f 100644 --- a/go.sum +++ b/go.sum @@ -18,7 +18,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.24.1/go.mod h1:fGP8eQ6PugKEI0iUETYYtnP6d1pH/bdDMTel1X5ajsU= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= @@ -65,6 +69,8 @@ github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7j github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -87,9 +93,20 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7 github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -212,12 +229,17 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kurin/blazer v0.5.4-0.20200327014341-8f90a40f8af7/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= @@ -340,6 +362,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -375,6 +398,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -402,7 +426,9 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJV golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -441,6 +467,7 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -466,7 +493,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190914235951-31e00f45c22e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk= golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -535,13 +564,19 @@ k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE= k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/client-go v0.18.0 h1:yqKw4cTUQraZK3fcVCMeSa+lqKwcjZ5wtcOIPnxQno4= k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= +k8s.io/code-generator v0.18.6 h1:QdfvGfs4gUCS1dru+rLbCKIFxYEV0IRfF8MXwY/ozLk= +k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 h1:RPscN6KhmG54S33L+lr3GS+oD1jmchIU0ll519K6FA4= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh new file mode 100755 index 00000000000..ac3fd059f03 --- /dev/null +++ b/hack/update-codegen.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# +# Copyright 2020 Google LLC +# +# 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 +# +# https://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. + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_ROOT=$(dirname ${BASH_SOURCE})/.. + +go get -d k8s.io/code-generator/... + +# Checkout code-generator to compatible version +#(cd $GOPATH/src/k8s.io/code-generator && git checkout origin/release-1.14 -B release-1.14) + +REPOSITORY=github.com/minio/minio-operator +$GOPATH/src/k8s.io/code-generator/generate-groups.sh all \ + $REPOSITORY/pkg/client $REPOSITORY/pkg/apis minio.min.io:v1 \ + --go-header-file $SCRIPT_ROOT/k8s.io/code-generator/hack/boilerplate.go.txt diff --git a/kustomization.yaml b/kustomization.yaml index 97bf720be7a..46818e1ea4b 100644 --- a/kustomization.yaml +++ b/kustomization.yaml @@ -10,7 +10,7 @@ replicas: images: - name: minio/k8s-operator newName: minio/k8s-operator - newTag: 2.0.9 + newTag: 3.0.0 # Configure the Cluster Domain and NameSpace to Watch configMapGenerator: diff --git a/minio-operator.yaml b/minio-operator.yaml index e452fe33d24..c74e05ca5ea 100644 --- a/minio-operator.yaml +++ b/minio-operator.yaml @@ -1,3 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: minio-operator +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -24,16 +29,42 @@ spec: type: object x-kubernetes-preserve-unknown-fields: true properties: - replicas: - type: integer - minimum: 1 - maximum: 32 + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true image: type: string serviceName: type: string - volumesPerServer: - type: integer + serviceAccountName: + type: string + zones: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + name: + type: string + servers: + type: integer + volumesPerServer: + type: integer + volumeClaimTemplate: + type: object + x-kubernetes-preserve-unknown-fields: true + resources: + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + type: object + x-kubernetes-preserve-unknown-fields: true + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + tolerations: + type: object + x-kubernetes-preserve-unknown-fields: true mountPath: type: string podManagementPolicy: @@ -43,26 +74,57 @@ spec: requestAutoCert: type: boolean default: false + certConfig: + type: object + properties: + commonName: + type: string + organizationName: + type: array + items: + type: string + dnsNames: + type: array + items: + type: string version: type: string mountpath: type: string subpath: type: string + nodeSelector: + type: object + x-kubernetes-preserve-unknown-fields: true + credsSecret: + type: object + x-kubernetes-preserve-unknown-fields: true + env: + type: object + x-kubernetes-preserve-unknown-fields: true console: type: object x-kubernetes-preserve-unknown-fields: true properties: + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true image: type: string replicas: type: integer default: 2 - mcsSecret: + consoleSecret: type: object properties: name: type: string + resources: + type: object + x-kubernetes-preserve-unknown-fields: true + env: + type: object + x-kubernetes-preserve-unknown-fields: true kes: type: object x-kubernetes-preserve-unknown-fields: true @@ -77,12 +139,15 @@ spec: properties: name: type: string - credsSecret: - type: object - x-kubernetes-preserve-unknown-fields: true - zones: + liveness: type: object - x-kubernetes-preserve-unknown-fields: true + properties: + initialDelaySeconds: + type: integer + periodSeconds: + type: integer + timeoutSeconds: + type: integer status: type: object properties: @@ -96,82 +161,82 @@ spec: type: string jsonPath: ".status.currentState" --- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: minio-operator-role -rules: -- apiGroups: - - "" - resources: - - namespaces - - secrets - - pods - - services - - events - verbs: - - get - - watch - - create - - list - - delete -- apiGroups: - - apps - resources: - - statefulsets - - deployments - verbs: - - get - - create - - list - - patch - - watch - - update - - delete -- apiGroups: - - batch - resources: - - jobs - verbs: - - get - - create - - list - - patch - - watch - - update - - delete -- apiGroups: - - "certificates.k8s.io" - resources: - - "certificatesigningrequests" - - "certificatesigningrequests/approval" - - "certificatesigningrequests/status" - verbs: - - update - - create - - get - - delete -- apiGroups: - - minio.min.io - resources: - - "*" - verbs: - - "*" -- apiGroups: - - min.io - resources: - - "*" - verbs: - - "*" ---- apiVersion: v1 kind: ServiceAccount metadata: name: minio-operator namespace: default --- -kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: minio-operator-role +rules: + - apiGroups: + - "" + resources: + - namespaces + - secrets + - pods + - services + - events + verbs: + - get + - watch + - create + - list + - delete + - apiGroups: + - apps + resources: + - statefulsets + - deployments + verbs: + - get + - create + - list + - patch + - watch + - update + - delete + - apiGroups: + - batch + resources: + - jobs + verbs: + - get + - create + - list + - patch + - watch + - update + - delete + - apiGroups: + - certificates.k8s.io + resources: + - certificatesigningrequests + - certificatesigningrequests/approval + - certificatesigningrequests/status + verbs: + - update + - create + - get + - delete + - apiGroups: + - minio.min.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - min.io + resources: + - '*' + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding metadata: name: minio-operator-binding roleRef: @@ -179,9 +244,9 @@ roleRef: kind: ClusterRole name: minio-operator-role subjects: -- kind: ServiceAccount - name: minio-operator - namespace: default + - kind: ServiceAccount + name: minio-operator + namespace: default --- apiVersion: apps/v1 kind: Deployment @@ -198,12 +263,8 @@ spec: labels: name: minio-operator spec: - serviceAccountName: minio-operator containers: - - name: minio-operator - image: minio/k8s-operator:2.0.9 + - image: minio/k8s-operator:3.0.0 imagePullPolicy: IfNotPresent - # To specify cluster domain, un comment the following: - # env: - # - name: CLUSTER_DOMAIN - # value: mycluster.mydomain + name: minio-operator + serviceAccountName: minio-operator diff --git a/operator-kustomize/crd.yaml b/operator-kustomize/crd.yaml index d2f5778a51c..dafba970f34 100644 --- a/operator-kustomize/crd.yaml +++ b/operator-kustomize/crd.yaml @@ -24,16 +24,42 @@ spec: type: object x-kubernetes-preserve-unknown-fields: true properties: - replicas: - type: integer - minimum: 1 - maximum: 32 + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true image: type: string serviceName: type: string - volumesPerServer: - type: integer + serviceAccountName: + type: string + zones: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + name: + type: string + servers: + type: integer + volumesPerServer: + type: integer + volumeClaimTemplate: + type: object + x-kubernetes-preserve-unknown-fields: true + resources: + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + type: object + x-kubernetes-preserve-unknown-fields: true + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + tolerations: + type: object + x-kubernetes-preserve-unknown-fields: true mountPath: type: string podManagementPolicy: @@ -43,26 +69,57 @@ spec: requestAutoCert: type: boolean default: false + certConfig: + type: object + properties: + commonName: + type: string + organizationName: + type: array + items: + type: string + dnsNames: + type: array + items: + type: string version: type: string mountpath: type: string subpath: type: string - mcs: + nodeSelector: + type: object + x-kubernetes-preserve-unknown-fields: true + credsSecret: + type: object + x-kubernetes-preserve-unknown-fields: true + env: + type: object + x-kubernetes-preserve-unknown-fields: true + console: type: object x-kubernetes-preserve-unknown-fields: true properties: + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true image: type: string replicas: type: integer default: 2 - mcsSecret: + consoleSecret: type: object properties: name: type: string + resources: + type: object + x-kubernetes-preserve-unknown-fields: true + env: + type: object + x-kubernetes-preserve-unknown-fields: true kes: type: object x-kubernetes-preserve-unknown-fields: true @@ -77,6 +134,15 @@ spec: properties: name: type: string + liveness: + type: object + properties: + initialDelaySeconds: + type: integer + periodSeconds: + type: integer + timeoutSeconds: + type: integer status: type: object properties: diff --git a/operator-kustomize/deployment.yaml b/operator-kustomize/deployment.yaml index b27d99a6fcc..0273c8d71a3 100644 --- a/operator-kustomize/deployment.yaml +++ b/operator-kustomize/deployment.yaml @@ -16,7 +16,7 @@ spec: serviceAccountName: minio-operator containers: - name: minio-operator - image: minio/k8s-operator:2.0.9 + image: minio/k8s-operator:3.0.0 imagePullPolicy: IfNotPresent env: - name: CLUSTER_DOMAIN diff --git a/pkg/apis/minio.min.io/v1/constants.go b/pkg/apis/minio.min.io/v1/constants.go index 057ae01bf35..550a064b7af 100644 --- a/pkg/apis/minio.min.io/v1/constants.go +++ b/pkg/apis/minio.min.io/v1/constants.go @@ -51,8 +51,8 @@ const CSRNameSuffix = "-csr" // MinIOCertPath is the path where all MinIO certs are mounted const MinIOCertPath = "/tmp/certs" -// InstanceLabel is applied to all components of a Tenant cluster -const InstanceLabel = "v1.min.io/instance" +// TenantLabel is applied to all components of a Tenant cluster +const TenantLabel = "v1.min.io/tenant" // MinIOPort specifies the default Tenant port number. const MinIOPort = 9000 @@ -70,7 +70,7 @@ const MinIOVolumeMountPath = "/export" const MinIOVolumeSubPath = "" // DefaultMinIOImage specifies the default MinIO Docker hub image -const DefaultMinIOImage = "minio/minio:RELEASE.2020-07-14T19-14-30Z" +const DefaultMinIOImage = "minio/minio:RELEASE.2020-07-22T00-26-33Z" // DefaultMinIOAccessKey specifies default access key for Tenant const DefaultMinIOAccessKey = "AKIAIOSFODNN7EXAMPLE" @@ -79,7 +79,7 @@ const DefaultMinIOAccessKey = "AKIAIOSFODNN7EXAMPLE" const DefaultMinIOSecretKey = "wJalrXUtnFEMIK7MDENGbPxRfiCYEXAMPLEKEY" // MinIOHLSvcNameSuffix specifies the suffix added to Tenant name to create a headless service -const MinIOHLSvcNameSuffix = "-hl-svc" +const MinIOHLSvcNameSuffix = "-hl" // DefaultServers specifies the default MinIO replicas to use for distributed deployment if not specified explicitly by user const DefaultServers = 1 @@ -102,33 +102,33 @@ const LivenessPeriod = 1 // LivenessTimeout specifies the timeout for the liveness probe to expect a response const LivenessTimeout = 1 -// MCS Related Constants +// Console Related Constants -// DefaultMCSImage specifies the latest MCS Docker hub image -const DefaultMCSImage = "minio/mcs:v0.2.0" +// DefaultConsoleImage specifies the latest Console Docker hub image +const DefaultConsoleImage = "minio/mcs:v0.2.0" -// MCSInstanceLabel is applied to the MCS pods of a Tenant cluster -const MCSInstanceLabel = "v1.min.io/mcs" +// ConsoleTenantLabel is applied to the Console pods of a Tenant cluster +const ConsoleTenantLabel = "v1.min.io/console" -// MCSPort specifies the default MCS port number. +// MCSPort specifies the default Console port number. const MCSPort = 9090 -// MCSServicePortName specifies the default MCS Service's port name. +// MCSServicePortName specifies the default Console Service's port name. const MCSServicePortName = "http-mcs" // MCSServiceNameSuffix specifies the suffix added to Tenant service name to create a service for mcs const MCSServiceNameSuffix = "-ui" -// MCSName specifies the default container name for MCS +// MCSName specifies the default container name for Console const MCSName = "-mcs" -// MCSAdminPolicyName denotes the policy name for MCS user +// MCSAdminPolicyName denotes the policy name for Console user const MCSAdminPolicyName = "mcsAdmin" -// MCSRestartPolicy defines the default restart policy for MCS Containers +// MCSRestartPolicy defines the default restart policy for Console Containers const MCSRestartPolicy = corev1.RestartPolicyAlways -// DefaultMCSReplicas specifies the default number of MCS pods to be created if not specified +// DefaultMCSReplicas specifies the default number of Console pods to be created if not specified const DefaultMCSReplicas = 2 // KES Related Constants diff --git a/pkg/apis/minio.min.io/v1/helper.go b/pkg/apis/minio.min.io/v1/helper.go index 2dc6d93d468..0c354f94e1f 100644 --- a/pkg/apis/minio.min.io/v1/helper.go +++ b/pkg/apis/minio.min.io/v1/helper.go @@ -97,23 +97,13 @@ func (t *Tenant) AutoCert() bool { return t.Spec.RequestAutoCert } -// VolumePath returns the paths for MinIO mounts based on -// total number of volumes per MinIO server -func (t *Tenant) VolumePath() string { - if t.Spec.VolumesPerServer == 1 { +// VolumePathForZone returns the paths for MinIO mounts based on +// total number of volumes on a given zone +func (t *Tenant) VolumePathForZone(zone *Zone) string { + if zone.VolumesPerServer == 1 { return path.Join(t.Spec.Mountpath, t.Spec.Subpath) } - return path.Join(t.Spec.Mountpath+ellipsis(0, t.Spec.VolumesPerServer-1), t.Spec.Subpath) -} - -// MinIOReplicas returns the number of total replicas -// required for this cluster -func (t *Tenant) MinIOReplicas() int32 { - var replicas int32 - for _, z := range t.Spec.Zones { - replicas = replicas + z.Servers - } - return replicas + return path.Join(t.Spec.Mountpath+ellipsis(0, int(zone.VolumesPerServer-1)), t.Spec.Subpath) } // KESReplicas returns the number of total KES replicas @@ -145,14 +135,11 @@ func (t *Tenant) EnsureDefaults() *Tenant { t.Spec.ServiceName = t.Name } - for _, z := range t.Spec.Zones { - if z.Servers == 0 { - z.Servers = DefaultServers + for zi, z := range t.Spec.Zones { + if z.Name == "" { + z.Name = fmt.Sprintf("zone-%d", zi) } - } - - if t.Spec.VolumesPerServer == 0 { - t.Spec.VolumesPerServer = DefaultVolumesPerServer + t.Spec.Zones[zi] = z } if t.Spec.Mountpath == "" { @@ -195,12 +182,12 @@ func (t *Tenant) EnsureDefaults() *Tenant { } } - if t.HasMCSEnabled() { - if t.Spec.MCS.Image == "" { - t.Spec.MCS.Image = DefaultMCSImage + if t.HasConsoleEnabled() { + if t.Spec.Console.Image == "" { + t.Spec.Console.Image = DefaultConsoleImage } - if t.Spec.MCS.Replicas == 0 { - t.Spec.MCS.Replicas = DefaultMCSReplicas + if t.Spec.Console.Replicas == 0 { + t.Spec.Console.Replicas = DefaultMCSReplicas } } @@ -219,12 +206,13 @@ func (t *Tenant) EnsureDefaults() *Tenant { // MinIOHosts returns the domain names in ellipses format created for current Tenant func (t *Tenant) MinIOHosts() []string { hosts := make([]string, 0) - var max, index int32 // Create the ellipses style URL for _, z := range t.Spec.Zones { - max = max + z.Servers - hosts = append(hosts, fmt.Sprintf("%s-%s.%s.%s.svc.%s", t.MinIOStatefulSetName(), ellipsis(int(index), int(max)-1), t.MinIOHLServiceName(), t.Namespace, ClusterDomain)) - index = max + if z.Servers == 1 { + hosts = append(hosts, fmt.Sprintf("%s-%s.%s.%s.svc.%s", t.MinIOStatefulSetNameForZone(&z), "0", t.MinIOHLServiceName(), t.Namespace, ClusterDomain)) + } else { + hosts = append(hosts, fmt.Sprintf("%s-%s.%s.%s.svc.%s", t.MinIOStatefulSetNameForZone(&z), ellipsis(0, int(z.Servers)-1), t.MinIOHLServiceName(), t.Namespace, ClusterDomain)) + } } return hosts } @@ -243,7 +231,7 @@ func (t *Tenant) TemplatedMinIOHosts(hostsTemplate string) []string { for _, z := range t.Spec.Zones { max = max + z.Servers data := hostsTemplateValues{ - StatefulSet: t.MinIOStatefulSetName(), + StatefulSet: t.MinIOStatefulSetNameForZone(&z), CIService: t.MinIOCIServiceName(), HLService: t.MinIOHLServiceName(), Ellipsis: ellipsis(int(index), int(max)-1), @@ -309,21 +297,21 @@ func (t *Tenant) HasKESEnabled() bool { return t.Spec.KES != nil } -// HasMCSEnabled checks if the mcs has been enabled by the user -func (t *Tenant) HasMCSEnabled() bool { - return t.Spec.MCS != nil +// HasConsoleEnabled checks if the mcs has been enabled by the user +func (t *Tenant) HasConsoleEnabled() bool { + return t.Spec.Console != nil } // HasMCSSecret returns true if the user has provided an mcs secret // for a Tenant else false func (t *Tenant) HasMCSSecret() bool { - return t.Spec.MCS != nil && t.Spec.MCS.MCSSecret != nil + return t.Spec.Console != nil && t.Spec.Console.ConsoleSecret != nil } // HasMCSMetadata returns true if the user has provided a mcs metadata // for a Tenant else false func (t *Tenant) HasMCSMetadata() bool { - return t.Spec.MCS != nil && t.Spec.MCS.Metadata != nil + return t.Spec.Console != nil && t.Spec.Console.Metadata != nil } // HasKESMetadata returns true if the user has provided KES metadata @@ -340,7 +328,7 @@ func (t *Tenant) CreateMCSUser(minioSecret, mcsSecret map[string][]byte) error { host := net.JoinHostPort(t.MinIOCIServiceHost(), strconv.Itoa(MinIOPort)) if host == "" { - return errors.New("MCS MINIO SERVER is empty") + return errors.New("Console MINIO SERVER is empty") } accessKey, ok = minioSecret["accesskey"] @@ -414,34 +402,48 @@ func (t *Tenant) CreateMCSUser(minioSecret, mcsSecret map[string][]byte) error { // Validate returns an error if any configuration of the MinIO instance is invalid func (t *Tenant) Validate() error { - // Mandate a VolumeClaimTemplate - if t.Spec.VolumeClaimTemplate == nil { - return errors.New("volume claim must be specified") - } - // Mandate a resource request - if t.Spec.VolumeClaimTemplate.Spec.Resources.Requests == nil { - return errors.New("volume claim must specify resource request") - } - // Mandate a request of storage - if t.Spec.VolumeClaimTemplate.Spec.Resources.Requests.Storage() == nil { - return errors.New("volume claim must specify resource storage request") - } - // Make sure the storage request is not 0 - if t.Spec.VolumeClaimTemplate.Spec.Resources.Requests.Storage().Value() <= 0 { - return errors.New("volume size must be greater than 0") - } if t.Spec.Zones == nil { - return errors.New("please provide a zone for Tenant") + return errors.New("zones were must be configured") + } + // every zone must contain a Volume Claim Template + for zi, zone := range t.Spec.Zones { + // Make sure the replicas are not 0 on any zone + if zone.Servers == 0 { + return fmt.Errorf("zone #%d cannot have 0 servers", zi) + } + // Make sure the zones don't have 0 volumes + if zone.VolumesPerServer == 0 { + return fmt.Errorf("zone #%d cannot have 0 volumes per server", zi) + } + // Distributed Setup can't have 2 or 3 disks only. Either 1 or 4+ volumes + if zone.Servers == 1 && (zone.VolumesPerServer == 2 || zone.VolumesPerServer == 3) { + return fmt.Errorf("distributed setup must have 4 or more volumes") + } + // Mandate a VolumeClaimTemplate + if zone.VolumeClaimTemplate == nil { + return errors.New("volume claim must be specified") + } + // Mandate a resource request + if zone.VolumeClaimTemplate.Spec.Resources.Requests == nil { + return errors.New("volume claim must specify resource request") + } + // Mandate a request of storage + if zone.VolumeClaimTemplate.Spec.Resources.Requests.Storage() == nil { + return errors.New("volume claim must specify resource storage request") + } + // Make sure the storage request is not 0 + if zone.VolumeClaimTemplate.Spec.Resources.Requests.Storage().Value() <= 0 { + return errors.New("volume size must be greater than 0") + } + // Make sure access mode is provided + if len(zone.VolumeClaimTemplate.Spec.AccessModes) == 0 { + return errors.New("volume access mode must be specified") + } } + if t.Spec.CredsSecret == nil { return errors.New("please set credsSecret secret with credentials for Tenant") } - // Make sure the replicas are not 0 on any zone - for _, z := range t.Spec.Zones { - if z.Servers == 0 { - return fmt.Errorf("zone '%s' cannot have 0 servers", z.Name) - } - } return nil } diff --git a/pkg/apis/minio.min.io/v1/helper_test.go b/pkg/apis/minio.min.io/v1/helper_test.go index 30edc164a85..afa7e373a4f 100644 --- a/pkg/apis/minio.min.io/v1/helper_test.go +++ b/pkg/apis/minio.min.io/v1/helper_test.go @@ -3,6 +3,8 @@ package v1 import ( "testing" + corev1 "k8s.io/api/core/v1" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -49,14 +51,25 @@ func TestTemplateVariables(t *testing.T) { mt := Tenant{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: TenantSpec{ - Zones: []Zone{{"single", int32(servers)}}, + Zones: []Zone{ + { + Name: "single", + Servers: int32(servers), + VolumesPerServer: 4, + VolumeClaimTemplate: nil, + Resources: corev1.ResourceRequirements{}, + NodeSelector: nil, + Affinity: nil, + Tolerations: nil, + }, + }, }, } mt.EnsureDefaults() t.Run("StatefulSet", func(t *testing.T) { hosts := mt.TemplatedMinIOHosts("{{.StatefulSet}}") - assert.Contains(t, hosts, mt.MinIOStatefulSetName()) + assert.Contains(t, hosts, mt.MinIOStatefulSetNameForZone(&mt.Spec.Zones[0])) }) t.Run("CIService", func(t *testing.T) { diff --git a/pkg/apis/minio.min.io/v1/labels.go b/pkg/apis/minio.min.io/v1/labels.go index 14a581a6cbb..4bd50c4d9ce 100644 --- a/pkg/apis/minio.min.io/v1/labels.go +++ b/pkg/apis/minio.min.io/v1/labels.go @@ -20,7 +20,7 @@ package v1 // MinIOPodLabels returns the default labels for MinIO Pod func (t *Tenant) MinIOPodLabels() map[string]string { m := make(map[string]string, 1) - m[InstanceLabel] = t.MinIOStatefulSetName() + m[TenantLabel] = t.Name return m } @@ -31,9 +31,9 @@ func (t *Tenant) KESPodLabels() map[string]string { return m } -// MCSPodLabels returns the default labels for MCS Pod +// MCSPodLabels returns the default labels for Console Pod func (t *Tenant) MCSPodLabels() map[string]string { m := make(map[string]string, 1) - m[MCSInstanceLabel] = t.MCSDeploymentName() + m[ConsoleTenantLabel] = t.MCSDeploymentName() return m } diff --git a/pkg/apis/minio.min.io/v1/names.go b/pkg/apis/minio.min.io/v1/names.go index 03570fa3709..65f3c101f50 100644 --- a/pkg/apis/minio.min.io/v1/names.go +++ b/pkg/apis/minio.min.io/v1/names.go @@ -27,14 +27,14 @@ const MinIOServerName = "tnio" // KESContainerName specifies the default container name for KES const KESContainerName = "kes" -// MCSContainerName specifies the default container name for MCS +// MCSContainerName specifies the default container name for Console const MCSContainerName = "mcs" // MinIO Related Names -// MinIOStatefulSetName returns the name for MinIO StatefulSet -func (t *Tenant) MinIOStatefulSetName() string { - return t.Name +// MinIOStatefulSetNameForZone returns the name for MinIO StatefulSet +func (t *Tenant) MinIOStatefulSetNameForZone(z *Zone) string { + return fmt.Sprintf("%s-%s", t.Name, z.Name) } // MinIOWildCardName returns the wild card name for all MinIO Pods in current StatefulSet @@ -115,14 +115,19 @@ func (t *Tenant) KESCSRName() string { return t.KESStatefulSetName() + CSRNameSuffix } -// MCS Related Names +// Console Related Names -// MCSDeploymentName returns the name for MCS Deployment +// MCSDeploymentName returns the name for Console Deployment func (t *Tenant) MCSDeploymentName() string { return t.Name + MCSName } -// MCSCIServiceName returns the name for MCS Cluster IP Service +// MCSCIServiceName returns the name for Console Cluster IP Service func (t *Tenant) MCSCIServiceName() string { return t.Name + MCSName } + +// ZoneStatefulsetName returns the name of a statefulset for a given zone +func (t *Tenant) ZoneStatefulsetName(zone *Zone) string { + return fmt.Sprintf("%s-%s", t.Name, zone.Name) +} diff --git a/pkg/apis/minio.min.io/v1/types.go b/pkg/apis/minio.min.io/v1/types.go index c6dc174dd8a..31d1f1cd560 100644 --- a/pkg/apis/minio.min.io/v1/types.go +++ b/pkg/apis/minio.min.io/v1/types.go @@ -47,6 +47,8 @@ type TenantScheduler struct { // TenantSpec is the spec for a Tenant resource type TenantSpec struct { + // Definition for Cluster in given MinIO cluster + Zones []Zone `json:"zones"` // Image defines the Tenant Docker image. // +optional Image string `json:"image,omitempty"` @@ -69,23 +71,6 @@ type TenantSpec struct { // If provided, use these environment variables for Tenant resource // +optional Env []corev1.EnvVar `json:"env,omitempty"` - // If provided, use these requests and limit for cpu/memory resource allocation - // +optional - Resources corev1.ResourceRequirements `json:"resources,omitempty"` - // VolumesPerServer allows a user to specify how many volumes per MinIO Server/Pod instance - // +optional - VolumesPerServer int `json:"volumesPerServer"` - // VolumeClaimTemplate allows a user to specify how volumes inside a Tenant - // +optional - VolumeClaimTemplate *corev1.PersistentVolumeClaim `json:"volumeClaimTemplate,omitempty"` - // NodeSelector is a selector which must be true for the pod to fit on a node. - // Selector which must match a node's labels for the pod to be scheduled on that node. - // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - // +optional - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - // If specified, affinity will define the pod's scheduling constraints - // +optional - Affinity *corev1.Affinity `json:"affinity,omitempty"` // ExternalCertSecret allows a user to specify custom CA certificate, and private key. This is // used for enabling TLS support on MinIO Pods. // +optional @@ -110,18 +95,12 @@ type TenantSpec struct { // CertConfig allows users to set entries like CommonName, Organization, etc for the certificate // +optional CertConfig *CertificateConfig `json:"certConfig,omitempty"` - // Tolerations allows users to set entries like effect, key, operator, value. - // +optional - Tolerations []corev1.Toleration `json:"tolerations,omitempty"` // Security Context allows user to set entries like runAsUser, privilege escalation etc. // +optional SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"` - // Definition for Cluster in given MinIO cluster - // +optional - Zones []Zone `json:"zones"` - // MCSConfig is for setting up minio/mcs for graphical user interface + // ConsoleConfiguration is for setting up minio/mcs for graphical user interface //+optional - MCS *MCSConfig `json:"mcs,omitempty"` + Console *ConsoleConfiguration `json:"console,omitempty"` // KES is for setting up minio/kes as MinIO KMS //+optional KES *KESConfig `json:"kes,omitempty"` @@ -152,8 +131,29 @@ type LocalCertificateReference struct { // Zone defines the spec for a MinIO Zone type Zone struct { - Name string `json:"name"` - Servers int32 `json:"servers"` + // Name of the zone + // +optional + Name string `json:"name,omitempty"` + // Number of Servers in the zone + Servers int32 `json:"servers"` + // Number of persistent volumes that will be attached per server + VolumesPerServer int32 `json:"volumesPerServer"` + // VolumeClaimTemplate allows a user to specify how volumes inside a Tenant + VolumeClaimTemplate *corev1.PersistentVolumeClaim `json:"volumeClaimTemplate"` + // If provided, use these requests and limit for cpu/memory resource allocation + // +optional + Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // NodeSelector is a selector which must be true for the pod to fit on a node. + // Selector which must match a node's labels for the pod to be scheduled on that node. + // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + // +optional + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // If specified, affinity will define the pod's scheduling constraints + // +optional + Affinity *corev1.Affinity `json:"affinity,omitempty"` + // Tolerations allows users to set entries like effect, key, operator, value. + // +optional + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` } // Liveness specifies the spec for liveness probe @@ -163,8 +163,8 @@ type Liveness struct { TimeoutSeconds int32 `json:"timeoutSeconds"` } -// MCSConfig defines the specifications for MCS Deployment -type MCSConfig struct { +// ConsoleConfiguration defines the specifications for Console Deployment +type ConsoleConfiguration struct { // Replicas defines number of pods for KES StatefulSet. // +optional Replicas int32 `json:"replicas,omitempty"` @@ -173,12 +173,18 @@ type MCSConfig struct { Image string `json:"image,omitempty"` // This secret provides all environment variables for KES // This is a mandatory field - MCSSecret *corev1.LocalObjectReference `json:"mcsSecret"` - Metadata *metav1.ObjectMeta `json:"metadata,omitempty"` + ConsoleSecret *corev1.LocalObjectReference `json:"consoleSecret"` + Metadata *metav1.ObjectMeta `json:"metadata,omitempty"` + // If provided, use these environment variables for Console resource + // +optional + Env []corev1.EnvVar `json:"env,omitempty"` + // If provided, use these requests and limit for cpu/memory resource allocation + // +optional + Resources corev1.ResourceRequirements `json:"resources,omitempty"` } // EqualImage returns true if config image and current input image are same -func (c MCSConfig) EqualImage(currentImage string) bool { +func (c ConsoleConfiguration) EqualImage(currentImage string) bool { return c.Image == currentImage } diff --git a/pkg/apis/minio.min.io/v1/zz_generated.deepcopy.go b/pkg/apis/minio.min.io/v1/zz_generated.deepcopy.go index e57c2d43215..b5249959c96 100644 --- a/pkg/apis/minio.min.io/v1/zz_generated.deepcopy.go +++ b/pkg/apis/minio.min.io/v1/zz_generated.deepcopy.go @@ -52,6 +52,40 @@ func (in *CertificateConfig) DeepCopy() *CertificateConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConsoleConfiguration) DeepCopyInto(out *ConsoleConfiguration) { + *out = *in + if in.ConsoleSecret != nil { + in, out := &in.ConsoleSecret, &out.ConsoleSecret + *out = new(corev1.LocalObjectReference) + **out = **in + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(metav1.ObjectMeta) + (*in).DeepCopyInto(*out) + } + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]corev1.EnvVar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Resources.DeepCopyInto(&out.Resources) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsoleConfiguration. +func (in *ConsoleConfiguration) DeepCopy() *ConsoleConfiguration { + if in == nil { + return nil + } + out := new(ConsoleConfiguration) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KESConfig) DeepCopyInto(out *KESConfig) { *out = *in @@ -115,32 +149,6 @@ func (in *LocalCertificateReference) DeepCopy() *LocalCertificateReference { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MCSConfig) DeepCopyInto(out *MCSConfig) { - *out = *in - if in.MCSSecret != nil { - in, out := &in.MCSSecret, &out.MCSSecret - *out = new(corev1.LocalObjectReference) - **out = **in - } - if in.Metadata != nil { - in, out := &in.Metadata, &out.Metadata - *out = new(metav1.ObjectMeta) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MCSConfig. -func (in *MCSConfig) DeepCopy() *MCSConfig { - if in == nil { - return nil - } - out := new(MCSConfig) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Tenant) DeepCopyInto(out *Tenant) { *out = *in @@ -222,6 +230,13 @@ func (in *TenantScheduler) DeepCopy() *TenantScheduler { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TenantSpec) DeepCopyInto(out *TenantSpec) { *out = *in + if in.Zones != nil { + in, out := &in.Zones, &out.Zones + *out = make([]Zone, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } out.ImagePullSecret = in.ImagePullSecret if in.Metadata != nil { in, out := &in.Metadata, &out.Metadata @@ -240,24 +255,6 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - in.Resources.DeepCopyInto(&out.Resources) - if in.VolumeClaimTemplate != nil { - in, out := &in.VolumeClaimTemplate, &out.VolumeClaimTemplate - *out = new(corev1.PersistentVolumeClaim) - (*in).DeepCopyInto(*out) - } - if in.NodeSelector != nil { - in, out := &in.NodeSelector, &out.NodeSelector - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Affinity != nil { - in, out := &in.Affinity, &out.Affinity - *out = new(corev1.Affinity) - (*in).DeepCopyInto(*out) - } if in.ExternalCertSecret != nil { in, out := &in.ExternalCertSecret, &out.ExternalCertSecret *out = new(LocalCertificateReference) @@ -278,26 +275,14 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) { *out = new(CertificateConfig) (*in).DeepCopyInto(*out) } - if in.Tolerations != nil { - in, out := &in.Tolerations, &out.Tolerations - *out = make([]corev1.Toleration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } if in.SecurityContext != nil { in, out := &in.SecurityContext, &out.SecurityContext *out = new(corev1.PodSecurityContext) (*in).DeepCopyInto(*out) } - if in.Zones != nil { - in, out := &in.Zones, &out.Zones - *out = make([]Zone, len(*in)) - copy(*out, *in) - } - if in.MCS != nil { - in, out := &in.MCS, &out.MCS - *out = new(MCSConfig) + if in.Console != nil { + in, out := &in.Console, &out.Console + *out = new(ConsoleConfiguration) (*in).DeepCopyInto(*out) } if in.KES != nil { @@ -337,6 +322,31 @@ func (in *TenantStatus) DeepCopy() *TenantStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Zone) DeepCopyInto(out *Zone) { *out = *in + if in.VolumeClaimTemplate != nil { + in, out := &in.VolumeClaimTemplate, &out.VolumeClaimTemplate + *out = new(corev1.PersistentVolumeClaim) + (*in).DeepCopyInto(*out) + } + in.Resources.DeepCopyInto(&out.Resources) + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(corev1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]corev1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } diff --git a/pkg/client/listers/minio.min.io/v1/tenant.go b/pkg/client/listers/minio.min.io/v1/tenant.go index e8cbd7f267c..11a17d161da 100644 --- a/pkg/client/listers/minio.min.io/v1/tenant.go +++ b/pkg/client/listers/minio.min.io/v1/tenant.go @@ -26,10 +26,8 @@ import ( ) // TenantLister helps list Tenants. -// All objects returned here must be treated as read-only. type TenantLister interface { // List lists all Tenants in the indexer. - // Objects returned here must be treated as read-only. List(selector labels.Selector) (ret []*v1.Tenant, err error) // Tenants returns an object that can list and get Tenants. Tenants(namespace string) TenantNamespaceLister @@ -60,13 +58,10 @@ func (s *tenantLister) Tenants(namespace string) TenantNamespaceLister { } // TenantNamespaceLister helps list and get Tenants. -// All objects returned here must be treated as read-only. type TenantNamespaceLister interface { // List lists all Tenants in the indexer for a given namespace. - // Objects returned here must be treated as read-only. List(selector labels.Selector) (ret []*v1.Tenant, err error) // Get retrieves the Tenant from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. Get(name string) (*v1.Tenant, error) TenantNamespaceListerExpansion } diff --git a/pkg/controller/cluster/main-controller.go b/pkg/controller/cluster/main-controller.go index 2a88a28830f..085525dd79d 100644 --- a/pkg/controller/cluster/main-controller.go +++ b/pkg/controller/cluster/main-controller.go @@ -23,6 +23,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "log" "time" "k8s.io/klog" @@ -75,20 +76,20 @@ const ( // is synced successfully MessageResourceSynced = "Tenant synced successfully" // Standard Status messages for Tenant - ready = "Ready" - addingZone = "Adding New MinIO Zone" - provisioningCIService = "Provisioning MinIO Cluster IP Service" - provisioningHLService = "Provisioning MinIO Headless Service" - provisioningStatefulSet = "Provisioning MinIO Statefulset" - provisioningMCSDeployment = "Provisioning MCS Deployment" - provisioningKESStatefulSet = "Provisioning KES StatefulSet" - waitingForReadyState = "Waiting for Pods to be ready" - waitingMinIOCert = "Waiting for MinIO TLS Certificate" - waitingMinIOClientCert = "Waiting for MinIO TLS Client Certificate" - waitingKESCert = "Waiting for KES TLS Certificate" - updatingMinIOVersion = "Updating MinIO Version" - updatingMCSVersion = "Updating MCS Version" - notOwned = "Statefulset not controlled by operator" + statusReady = "Ready" + statusAddingZone = "Adding New MinIO Zone" + statusProvisioningCIService = "Provisioning MinIO Cluster IP Service" + statusProvisioningHLService = "Provisioning MinIO Headless Service" + statusProvisioningStatefulSet = "Provisioning MinIO Statefulset" + statusProvisioningMCSDeployment = "Provisioning Console Deployment" + statusProvisioningKESStatefulSet = "Provisioning KES StatefulSet" + statusWaitingForReadyState = "Waiting for Pods to be ready" + statusWaitingMinIOCert = "Waiting for MinIO TLS Certificate" + statusWaitingMinIOClientCert = "Waiting for MinIO TLS Client Certificate" + statusWaitingKESCert = "Waiting for KES TLS Certificate" + statusUpdatingMinIOVersion = "Updating MinIO Version" + statusUpdatingConsoleVersion = "Updating Console Version" + statusNotOwned = "Statefulset not controlled by operator" ) // Controller struct watches the Kubernetes API for changes to Tenant resources @@ -352,23 +353,20 @@ func (c *Controller) syncHandler(key string) error { runtime.HandleError(fmt.Errorf("Tenant '%s' in work queue no longer exists", key)) return nil } - return err + return nil } - // Set any required default values and init Global variables nsName := types.NamespacedName{Namespace: namespace, Name: name} - mi.EnsureDefaults() + mi = mi.EnsureDefaults() miniov1.InitGlobals(mi) - // Validate the MinIO Instance if err = mi.Validate(); err != nil { klog.V(2).Infof(err.Error()) var err2 error - mi, err2 = c.updateTenantStatus(ctx, mi, err.Error(), 0) - if err2 != nil { + if mi, err2 = c.updateTenantStatus(ctx, mi, err.Error(), 0); err2 != nil { klog.V(2).Infof(err2.Error()) } - return err + return nil } // check if both auto certificate creation and external secret with certificate is passed, @@ -376,7 +374,11 @@ func (c *Controller) syncHandler(key string) error { if mi.AutoCert() && (mi.ExternalCert() || mi.ExternalClientCert() || mi.KESExternalCert()) { msg := "Please set either externalCertSecret or requestAutoCert in Tenant config" klog.V(2).Infof(msg) - return fmt.Errorf(msg) + var err2 error + if mi, err2 = c.updateTenantStatus(ctx, mi, msg, 0); err2 != nil { + klog.V(2).Infof(err2.Error()) + } + return nil } // TLS is mandatory if KES is enabled @@ -387,7 +389,11 @@ func (c *Controller) syncHandler(key string) error { if !(mi.ExternalCert() && mi.ExternalClientCert() && mi.KESExternalCert()) { msg := "Please provide certificate secrets for MinIO and KES, since automatic TLS is disabled" klog.V(2).Infof(msg) - return fmt.Errorf(msg) + var err2 error + if mi, err2 = c.updateTenantStatus(ctx, mi, msg, 0); err2 != nil { + klog.V(2).Infof(err2.Error()) + } + return nil } } @@ -395,11 +401,11 @@ func (c *Controller) syncHandler(key string) error { svc, err := c.serviceLister.Services(mi.Namespace).Get(mi.MinIOCIServiceName()) if err != nil { if apierrors.IsNotFound(err) { - mi, err = c.updateTenantStatus(ctx, mi, provisioningCIService, 0) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusProvisioningCIService, 0); err != nil { return err } klog.V(2).Infof("Creating a new Cluster IP Service for cluster %q", nsName) + // Create the clusterIP service for the Tenant svc = services.NewClusterIPForMinIO(mi) _, err = c.kubeClientSet.CoreV1().Services(mi.Namespace).Create(ctx, svc, cOpts) if err != nil { @@ -414,11 +420,11 @@ func (c *Controller) syncHandler(key string) error { hlSvc, err := c.serviceLister.Services(mi.Namespace).Get(mi.MinIOHLServiceName()) if err != nil { if apierrors.IsNotFound(err) { - mi, err = c.updateTenantStatus(ctx, mi, provisioningHLService, 0) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusProvisioningHLService, 0); err != nil { return err } klog.V(2).Infof("Creating a new Headless Service for cluster %q", nsName) + // Create the headless service for the tenant hlSvc = services.NewHeadlessForMinIO(mi) _, err = c.kubeClientSet.CoreV1().Services(mi.Namespace).Create(ctx, hlSvc, cOpts) if err != nil { @@ -429,74 +435,84 @@ func (c *Controller) syncHandler(key string) error { } } - // Get the StatefulSet with the name specified in Tenant.spec - ss, err := c.statefulSetLister.StatefulSets(mi.Namespace).Get(mi.Name) - if err != nil { - if apierrors.IsNotFound(err) { - // If auto cert is enabled, create certificates for MinIO and - // optionally KES - if mi.AutoCert() { - // Client cert is needed only with KES for mTLS authentication - if err = c.checkAndCreateMinIOCSR(ctx, nsName, mi, mi.HasKESEnabled()); err != nil { - return err - } - if mi.HasKESEnabled() { - if err = c.checkAndCreateKESCSR(ctx, nsName, mi); err != nil { + // For each zone check it's stateful set + var totalReplicas int32 + for _, zone := range mi.Spec.Zones { + // Get the StatefulSet with the name specified in Tenant.spec + ss, err := c.statefulSetLister.StatefulSets(mi.Namespace).Get(mi.ZoneStatefulsetName(&zone)) + if err != nil { + if apierrors.IsNotFound(err) { + // If auto cert is enabled, create certificates for MinIO and + // optionally KES + if mi.AutoCert() { + // Client cert is needed only with KES for mTLS authentication + if err = c.checkAndCreateMinIOCSR(ctx, nsName, mi, mi.HasKESEnabled()); err != nil { return err } + if mi.HasKESEnabled() { + if err = c.checkAndCreateKESCSR(ctx, nsName, mi); err != nil { + return err + } + } } - } - mi, err = c.updateTenantStatus(ctx, mi, provisioningStatefulSet, 0) - if err != nil { - return err - } - ss = statefulsets.NewForMinIO(mi, hlSvc.Name, c.hostsTemplate) - ss, err = c.kubeClientSet.AppsV1().StatefulSets(mi.Namespace).Create(ctx, ss, cOpts) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusProvisioningStatefulSet, 0); err != nil { + return err + } + ss = statefulsets.NewForMinIOZone(mi, &zone, hlSvc.Name, c.hostsTemplate) + ss, err = c.kubeClientSet.AppsV1().StatefulSets(mi.Namespace).Create(ctx, ss, cOpts) + if err != nil { + log.Println("ERROR CREATING SS", zone.Name) + log.Println(err) + return err + } + } else { return err } } else { - return err - } - } else { - // If the number of the replicas on the Tenant resource is specified, and the - // number does not equal the current desired replicas on the StatefulSet, we - // should update the StatefulSet resource. - // If the status already indicates "addingZone", no need for another - // thread to enter this block - we don't want to get in a race for deletion and creation of CSRs - if mi.MinIOReplicas() != *ss.Spec.Replicas && mi.Status.CurrentState != addingZone { - // save current replicas before creating new statefulset - // this is used later to delete only the older pods in statefulset - mi, err = c.updateTenantStatus(ctx, mi, addingZone, 0) - if err != nil { - return err + // If the number of the replicas on the Tenant resource is specified, and the + // number does not equal the current desired replicas on the StatefulSet, we + // should update the StatefulSet resource. + // If the status already indicates "statusAddingZone", no need for another + // thread to enter this block - we don't want to get in a race for deletion and creation of CSRs + if zone.Servers != *ss.Spec.Replicas && mi.Status.CurrentState != statusAddingZone { + // save current replicas before creating new statefulset + // this is used later to delete only the older pods in statefulset + if mi, err = c.updateTenantStatus(ctx, mi, fmt.Sprintf("Can't modify server count for zone %s", zone.Name), 0); err != nil { + return err + } + klog.V(2).Infof("Creating a new StatefulSet %s with replicas: %d", name, zone.Servers) } - klog.V(2).Infof("Creating a new StatefulSet %s with replicas: %d", name, mi.MinIOReplicas()) - // Create a new statefulset object and send an update request - // Even if this is an autoTLS enabled setup, the certs are wild card certs e.g. *. - ss = statefulsets.NewForMinIO(mi, hlSvc.Name, c.hostsTemplate) - if _, err := c.kubeClientSet.AppsV1().StatefulSets(mi.Namespace).Update(ctx, ss, uOpts); err != nil { - return err + + // If this container version on the Tenant resource is specified, and the + // version does not equal the current desired version in the StatefulSet, we + // should update the StatefulSet resource. + if mi.Spec.Image != ss.Spec.Template.Spec.Containers[0].Image { + if mi, err = c.updateTenantStatus(ctx, mi, statusUpdatingMinIOVersion, ss.Status.Replicas); err != nil { + return err + } + klog.V(4).Infof("Updating Tenant %s MinIO server version %s, to: %s", name, mi.Spec.Image, ss.Spec.Template.Spec.Containers[0].Image) + ss = statefulsets.NewForMinIOZone(mi, &zone, hlSvc.Name, c.hostsTemplate) + if _, err := c.kubeClientSet.AppsV1().StatefulSets(mi.Namespace).Update(ctx, ss, uOpts); err != nil { + return err + } } } - // If this container version on the Tenant resource is specified, and the - // version does not equal the current desired version in the StatefulSet, we - // should update the StatefulSet resource. - if mi.Spec.Image != ss.Spec.Template.Spec.Containers[0].Image { - mi, err = c.updateTenantStatus(ctx, mi, updatingMinIOVersion, ss.Status.Replicas) - if err != nil { - return err - } - klog.V(4).Infof("Updating Tenant %s MinIO server version %s, to: %s", name, mi.Spec.Image, ss.Spec.Template.Spec.Containers[0].Image) - ss = statefulsets.NewForMinIO(mi, hlSvc.Name, c.hostsTemplate) - if _, err := c.kubeClientSet.AppsV1().StatefulSets(mi.Namespace).Update(ctx, ss, uOpts); err != nil { + // If the StatefulSet is not controlled by this Tenant resource, we should log + // a warning to the event recorder and ret + if !metav1.IsControlledBy(ss, mi) { + if mi, err = c.updateTenantStatus(ctx, mi, statusNotOwned, ss.Status.Replicas); err != nil { return err } + msg := fmt.Sprintf(MessageResourceExists, ss.Name) + c.recorder.Event(mi, corev1.EventTypeWarning, ErrResourceExists, msg) + return fmt.Errorf(msg) } + // keep track of all replicas + totalReplicas += ss.Status.Replicas } - if mi.HasMCSEnabled() { + if mi.HasConsoleEnabled() { // Get the Deployment with the name specified in MirrorInstace.spec if _, err := c.deploymentLister.Deployments(mi.Namespace).Get(mi.MCSDeploymentName()); err != nil { if apierrors.IsNotFound(err) { @@ -512,29 +528,28 @@ func (c *Controller) syncHandler(key string) error { return sErr } - mcsSecretName := mi.Spec.MCS.MCSSecret.Name + mcsSecretName := mi.Spec.Console.ConsoleSecret.Name mcsSecret, sErr := c.kubeClientSet.CoreV1().Secrets(mi.Namespace).Get(ctx, mcsSecretName, gOpts) if sErr != nil { return sErr } // Check if any one replica is READY - if ss.Status.ReadyReplicas > 0 { - mi, err = c.updateTenantStatus(ctx, mi, provisioningMCSDeployment, ss.Status.Replicas) - if err != nil { + if totalReplicas > 0 { + if mi, err = c.updateTenantStatus(ctx, mi, statusProvisioningMCSDeployment, totalReplicas); err != nil { return err } if pErr := mi.CreateMCSUser(minioSecret.Data, mcsSecret.Data); pErr != nil { klog.V(2).Infof(pErr.Error()) return pErr } - // Create MCS Deployment + // Create Console Deployment mcsDeployment = deployments.NewForMCS(mi) _, err = c.kubeClientSet.AppsV1().Deployments(mi.Namespace).Create(ctx, mcsDeployment, cOpts) if err != nil { klog.V(2).Infof(err.Error()) return err } - // Create MCS service + // Create Console service mcsSvc := services.NewClusterIPForMCS(mi) _, err = c.kubeClientSet.CoreV1().Services(svc.Namespace).Create(ctx, mcsSvc, cOpts) if err != nil { @@ -542,8 +557,7 @@ func (c *Controller) syncHandler(key string) error { return err } } else { - mi, err = c.updateTenantStatus(ctx, mi, waitingForReadyState, ss.Status.Replicas) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusWaitingForReadyState, totalReplicas); err != nil { return err } } @@ -575,8 +589,7 @@ func (c *Controller) syncHandler(key string) error { // Get the StatefulSet with the name specified in spec if _, err = c.statefulSetLister.StatefulSets(mi.Namespace).Get(mi.KESStatefulSetName()); err != nil { if apierrors.IsNotFound(err) { - mi, err = c.updateTenantStatus(ctx, mi, provisioningKESStatefulSet, 0) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusProvisioningKESStatefulSet, 0); err != nil { return err } ks := statefulsets.NewForKES(mi, svc.Name) @@ -605,25 +618,12 @@ func (c *Controller) syncHandler(key string) error { } } - // If the StatefulSet is not controlled by this Tenant resource, we should log - // a warning to the event recorder and ret - if !metav1.IsControlledBy(ss, mi) { - mi, err = c.updateTenantStatus(ctx, mi, notOwned, ss.Status.Replicas) - if err != nil { + if mi.HasConsoleEnabled() && mcsDeployment != nil && !mi.Spec.Console.EqualImage(mcsDeployment.Spec.Template.Spec.Containers[0].Image) { + if mi, err = c.updateTenantStatus(ctx, mi, statusUpdatingConsoleVersion, totalReplicas); err != nil { return err } - msg := fmt.Sprintf(MessageResourceExists, ss.Name) - c.recorder.Event(mi, corev1.EventTypeWarning, ErrResourceExists, msg) - return fmt.Errorf(msg) - } - - if mi.HasMCSEnabled() && mcsDeployment != nil && !mi.Spec.MCS.EqualImage(mcsDeployment.Spec.Template.Spec.Containers[0].Image) { - mi, err = c.updateTenantStatus(ctx, mi, updatingMCSVersion, ss.Status.Replicas) - if err != nil { - return err - } - klog.V(4).Infof("Updating Tenant %s mcs version %s, to: %s", name, - mi.Spec.MCS.Image, mcsDeployment.Spec.Template.Spec.Containers[0].Image) + klog.V(4).Infof("Updating Tenant %s console version %s, to: %s", name, + mi.Spec.Console.Image, mcsDeployment.Spec.Template.Spec.Containers[0].Image) mcsDeployment = deployments.NewForMCS(mi) _, err = c.kubeClientSet.AppsV1().Deployments(mi.Namespace).Update(ctx, mcsDeployment, uOpts) // If an error occurs during Update, we'll requeue the item so we can @@ -636,15 +636,14 @@ func (c *Controller) syncHandler(key string) error { // Finally, we update the status block of the Tenant resource to reflect the // current state of the world - _, err = c.updateTenantStatus(ctx, mi, ready, ss.Status.Replicas) + _, err = c.updateTenantStatus(ctx, mi, statusReady, totalReplicas) return err } func (c *Controller) checkAndCreateMinIOCSR(ctx context.Context, nsName types.NamespacedName, mi *miniov1.Tenant, createClientCert bool) error { if _, err := c.certClient.CertificateSigningRequests().Get(ctx, mi.MinIOCSRName(), metav1.GetOptions{}); err != nil { if apierrors.IsNotFound(err) { - mi, err = c.updateTenantStatus(ctx, mi, waitingMinIOCert, 0) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusWaitingMinIOCert, 0); err != nil { return err } klog.V(2).Infof("Creating a new Certificate Signing Request for MinIO Server Certs, cluster %q", nsName) @@ -658,8 +657,7 @@ func (c *Controller) checkAndCreateMinIOCSR(ctx context.Context, nsName types.Na if createClientCert { if _, err := c.certClient.CertificateSigningRequests().Get(ctx, mi.MinIOClientCSRName(), metav1.GetOptions{}); err != nil { if apierrors.IsNotFound(err) { - mi, err = c.updateTenantStatus(ctx, mi, waitingMinIOClientCert, 0) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusWaitingMinIOClientCert, 0); err != nil { return err } klog.V(2).Infof("Creating a new Certificate Signing Request for MinIO Client Certs, cluster %q", nsName) @@ -677,8 +675,7 @@ func (c *Controller) checkAndCreateMinIOCSR(ctx context.Context, nsName types.Na func (c *Controller) checkAndCreateKESCSR(ctx context.Context, nsName types.NamespacedName, mi *miniov1.Tenant) error { if _, err := c.certClient.CertificateSigningRequests().Get(ctx, mi.KESCSRName(), metav1.GetOptions{}); err != nil { if apierrors.IsNotFound(err) { - mi, err = c.updateTenantStatus(ctx, mi, waitingKESCert, 0) - if err != nil { + if mi, err = c.updateTenantStatus(ctx, mi, statusWaitingKESCert, 0); err != nil { return err } klog.V(2).Infof("Creating a new Certificate Signing Request for KES Server Certs, cluster %q", nsName) @@ -735,7 +732,9 @@ func (c *Controller) updateTenantStatus(ctx context.Context, tenant *miniov1.Ten // we must use Update instead of UpdateStatus to update the Status block of the Tenant resource. // UpdateStatus will not allow changes to the Spec of the resource, // which is ideal for ensuring nothing other than resource status has been updated. - return c.minioClientSet.MinioV1().Tenants(tenant.Namespace).UpdateStatus(ctx, tenantCopy, opts) + t, err := c.minioClientSet.MinioV1().Tenants(tenant.Namespace).UpdateStatus(ctx, tenantCopy, opts) + t.EnsureDefaults() + return t, err } // enqueueTenant takes a Tenant resource and converts it into a namespace/name diff --git a/pkg/resources/deployments/mcs-deployment.go b/pkg/resources/deployments/mcs-deployment.go index f2279aca352..1355d9e5942 100644 --- a/pkg/resources/deployments/mcs-deployment.go +++ b/pkg/resources/deployments/mcs-deployment.go @@ -27,8 +27,8 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Adds required MCS environment variables -func mcsEnvVars(t *miniov1.Tenant) []corev1.EnvVar { +// Adds required Console environment variables +func consoleEnvVars(t *miniov1.Tenant) []corev1.EnvVar { envVars := []corev1.EnvVar{ { Name: "MCS_MINIO_SERVER", @@ -41,16 +41,18 @@ func mcsEnvVars(t *miniov1.Tenant) []corev1.EnvVar { Value: "on", }) } + // Add all the environment variables + envVars = append(envVars, t.Spec.Console.Env...) return envVars } -// Returns the MCS environment variables set in configuration. -func mcsSecretEnvVars(t *miniov1.Tenant) []corev1.EnvFromSource { +// Returns the Console environment variables set in configuration. +func consoleSecretEnvVars(t *miniov1.Tenant) []corev1.EnvFromSource { envVars := []corev1.EnvFromSource{ { SecretRef: &corev1.SecretEnvSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: t.Spec.MCS.MCSSecret.Name, + Name: t.Spec.Console.ConsoleSecret.Name, }, }, }, @@ -61,7 +63,7 @@ func mcsSecretEnvVars(t *miniov1.Tenant) []corev1.EnvFromSource { func mcsMetadata(t *miniov1.Tenant) metav1.ObjectMeta { meta := metav1.ObjectMeta{} if t.HasMCSMetadata() { - meta = *t.Spec.MCS.Metadata + meta = *t.Spec.Console.Metadata } if meta.Labels == nil { meta.Labels = make(map[string]string) @@ -72,20 +74,20 @@ func mcsMetadata(t *miniov1.Tenant) metav1.ObjectMeta { return meta } -// mcsSelector Returns the MCS pods selector +// mcsSelector Returns the Console pods selector func mcsSelector(t *miniov1.Tenant) *metav1.LabelSelector { return &metav1.LabelSelector{ MatchLabels: t.MCSPodLabels(), } } -// Builds the MCS container for a Tenant. +// Builds the Console container for a Tenant. func mcsContainer(t *miniov1.Tenant) corev1.Container { args := []string{"server"} return corev1.Container{ Name: miniov1.MCSContainerName, - Image: t.Spec.MCS.Image, + Image: t.Spec.Console.Image, Ports: []corev1.ContainerPort{ { ContainerPort: miniov1.MCSPort, @@ -93,9 +95,9 @@ func mcsContainer(t *miniov1.Tenant) corev1.Container { }, ImagePullPolicy: miniov1.DefaultImagePullPolicy, Args: args, - Env: mcsEnvVars(t), - EnvFrom: mcsSecretEnvVars(t), - Resources: t.Spec.Resources, + Env: consoleEnvVars(t), + EnvFrom: consoleSecretEnvVars(t), + Resources: t.Spec.Console.Resources, } } @@ -109,8 +111,8 @@ func NewForMCS(t *miniov1.Tenant) *appsv1.Deployment { OwnerReferences: t.OwnerRef(), }, Spec: appsv1.DeploymentSpec{ - Replicas: &t.Spec.MCS.Replicas, - // MCS is always matched via Tenant Name + mcs prefix + Replicas: &t.Spec.Console.Replicas, + // Console is always matched via Tenant Name + mcs prefix Selector: mcsSelector(t), Template: corev1.PodTemplateSpec{ ObjectMeta: mcsMetadata(t), diff --git a/pkg/resources/services/service.go b/pkg/resources/services/service.go index b1cb4e84ea9..1479428c402 100644 --- a/pkg/resources/services/service.go +++ b/pkg/resources/services/service.go @@ -86,7 +86,7 @@ func NewHeadlessForKES(t *miniov1.Tenant) *corev1.Service { return svc } -// NewClusterIPForMCS will return a new cluster IP service for MCS Deployment +// NewClusterIPForMCS will return a new cluster IP service for Console Deployment func NewClusterIPForMCS(t *miniov1.Tenant) *corev1.Service { minioPort := corev1.ServicePort{Port: miniov1.MCSPort, Name: miniov1.MCSServicePortName} svc := &corev1.Service{ diff --git a/pkg/resources/statefulsets/minio-statefulset.go b/pkg/resources/statefulsets/minio-statefulset.go index c1bbbfb9da3..1ff13b2ca13 100644 --- a/pkg/resources/statefulsets/minio-statefulset.go +++ b/pkg/resources/statefulsets/minio-statefulset.go @@ -90,7 +90,7 @@ func minioEnvironmentVars(t *miniov1.Tenant) []corev1.EnvVar { // Returns the MinIO pods metadata set in configuration. // If a user specifies metadata in the spec we return that // metadata. -func minioMetadata(t *miniov1.Tenant) metav1.ObjectMeta { +func minioMetadata(t *miniov1.Tenant, zone *miniov1.Zone) metav1.ObjectMeta { meta := metav1.ObjectMeta{} if t.HasMetadata() { meta = *t.Spec.Metadata @@ -113,21 +113,21 @@ func MinIOSelector(t *miniov1.Tenant) *metav1.LabelSelector { } // Builds the volume mounts for MinIO container. -func volumeMounts(t *miniov1.Tenant) (mounts []corev1.VolumeMount) { +func volumeMounts(t *miniov1.Tenant, zone *miniov1.Zone) (mounts []corev1.VolumeMount) { // This is the case where user didn't provide a zone and we deploy a EmptyDir based // single node single drive (FS) MinIO deployment name := miniov1.MinIOVolumeName - if t.Spec.VolumeClaimTemplate != nil { - name = t.Spec.VolumeClaimTemplate.Name + if zone.VolumeClaimTemplate != nil { + name = zone.VolumeClaimTemplate.Name } - if t.Spec.VolumesPerServer == 1 { + if zone.VolumesPerServer == 1 { mounts = append(mounts, corev1.VolumeMount{ Name: name + strconv.Itoa(0), MountPath: t.Spec.Mountpath, }) } else { - for i := 0; i < t.Spec.VolumesPerServer; i++ { + for i := 0; i < int(zone.VolumesPerServer); i++ { mounts = append(mounts, corev1.VolumeMount{ Name: name + strconv.Itoa(i), MountPath: t.Spec.Mountpath + strconv.Itoa(i), @@ -170,12 +170,12 @@ func probes(t *miniov1.Tenant) (liveness *corev1.Probe) { } // Builds the MinIO container for a Tenant. -func minioServerContainer(t *miniov1.Tenant, serviceName string, hostsTemplate string) corev1.Container { +func zoneMinioServerContainer(t *miniov1.Tenant, zone *miniov1.Zone, hostsTemplate string) corev1.Container { args := []string{"server", "--certs-dir", miniov1.MinIOCertPath} - if t.Spec.Zones[0].Servers == 1 { + if len(t.Spec.Zones) == 1 && t.Spec.Zones[0].Servers == 1 { // to run in standalone mode we must pass the path - args = append(args, t.VolumePath()) + args = append(args, t.VolumePathForZone(zone)) } else { // append all the Tenant replica URLs hosts := t.MinIOHosts() @@ -183,7 +183,7 @@ func minioServerContainer(t *miniov1.Tenant, serviceName string, hostsTemplate s hosts = t.TemplatedMinIOHosts(hostsTemplate) } for _, h := range hosts { - args = append(args, fmt.Sprintf("%s://"+h+"%s", miniov1.Scheme, t.VolumePath())) + args = append(args, fmt.Sprintf("%s://"+h+"%s", miniov1.Scheme, t.VolumePathForZone(zone))) } } @@ -198,18 +198,18 @@ func minioServerContainer(t *miniov1.Tenant, serviceName string, hostsTemplate s }, }, ImagePullPolicy: miniov1.DefaultImagePullPolicy, - VolumeMounts: volumeMounts(t), + VolumeMounts: volumeMounts(t, zone), Args: args, Env: minioEnvironmentVars(t), - Resources: t.Spec.Resources, + Resources: zone.Resources, LivenessProbe: liveProbe, } } -// Builds the tolerations for a Tenant. -func minioTolerations(t *miniov1.Tenant) []corev1.Toleration { +// Builds the tolerations for a Zone. +func minioZoneTolerations(z *miniov1.Zone) []corev1.Toleration { var tolerations []corev1.Toleration - return append(tolerations, t.Spec.Tolerations...) + return append(tolerations, z.Tolerations...) } // Builds the security context for a Tenant @@ -221,10 +221,10 @@ func minioSecurityContext(t *miniov1.Tenant) *corev1.PodSecurityContext { return &securityContext } -// NewForMinIO creates a new StatefulSet for the given Cluster. -func NewForMinIO(t *miniov1.Tenant, serviceName string, hostsTemplate string) *appsv1.StatefulSet { +// NewForMinIOZone creates a new StatefulSet for the given Cluster. +func NewForMinIOZone(t *miniov1.Tenant, zone *miniov1.Zone, serviceName string, hostsTemplate string) *appsv1.StatefulSet { var podVolumes []corev1.Volume - var replicas = t.MinIOReplicas() + var replicas = zone.Servers var serverCertSecret string var serverCertPaths = []corev1.KeyToPath{ {Key: "public.crt", Path: "public.crt"}, @@ -325,12 +325,12 @@ func NewForMinIO(t *miniov1.Tenant, serviceName string, hostsTemplate string) *a }) } - containers := []corev1.Container{minioServerContainer(t, serviceName, hostsTemplate)} + containers := []corev1.Container{zoneMinioServerContainer(t, zone, hostsTemplate)} ss := &appsv1.StatefulSet{ ObjectMeta: metav1.ObjectMeta{ Namespace: t.Namespace, - Name: t.Name, + Name: t.ZoneStatefulsetName(zone), OwnerReferences: []metav1.OwnerReference{ *metav1.NewControllerRef(t, schema.GroupVersionKind{ Group: miniov1.SchemeGroupVersion.Group, @@ -348,14 +348,14 @@ func NewForMinIO(t *miniov1.Tenant, serviceName string, hostsTemplate string) *a ServiceName: serviceName, Replicas: &replicas, Template: corev1.PodTemplateSpec{ - ObjectMeta: minioMetadata(t), + ObjectMeta: minioMetadata(t, zone), Spec: corev1.PodSpec{ Containers: containers, Volumes: podVolumes, RestartPolicy: corev1.RestartPolicyAlways, - Affinity: t.Spec.Affinity, + Affinity: zone.Affinity, SchedulerName: t.Scheduler.Name, - Tolerations: minioTolerations(t), + Tolerations: minioZoneTolerations(zone), SecurityContext: minioSecurityContext(t), ServiceAccountName: t.Spec.ServiceAccountName, }, @@ -368,10 +368,10 @@ func NewForMinIO(t *miniov1.Tenant, serviceName string, hostsTemplate string) *a ss.Spec.Template.Spec.ImagePullSecrets = []corev1.LocalObjectReference{t.Spec.ImagePullSecret} } - if t.Spec.VolumeClaimTemplate != nil { - pvClaim := *t.Spec.VolumeClaimTemplate + if zone.VolumeClaimTemplate != nil { + pvClaim := *zone.VolumeClaimTemplate name := pvClaim.Name - for i := 0; i < t.Spec.VolumesPerServer; i++ { + for i := 0; i < int(zone.VolumesPerServer); i++ { pvClaim.Name = name + strconv.Itoa(i) ss.Spec.VolumeClaimTemplates = append(ss.Spec.VolumeClaimTemplates, pvClaim) } diff --git a/testing/README.md b/testing/README.md new file mode 100644 index 00000000000..4af35a67142 --- /dev/null +++ b/testing/README.md @@ -0,0 +1,10 @@ +MinIO Operator Functional Testing +===== + +This folder contains a series of files to perform functional testing of `MinIO Operator`. + +> **WARNING**: :warning: These files are not intended to be used as examples + +All the files under `validations` will cause the MinIO Tenant to go into an error state. + + diff --git a/testing/four-zones.yaml b/testing/four-zones.yaml new file mode 100644 index 00000000000..c1d56389450 --- /dev/null +++ b/testing/four-zones.yaml @@ -0,0 +1,62 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-minio-creds-secret +type: Opaque +data: + accesskey: bWluaW8= # base 64 encoded "minio" (echo -n 'minio' | base64) + secretkey: bWluaW8xMjM= # based 64 encoded "minio123" (echo -n 'minio123' | base64) +--- +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: four-zones +spec: + zones: + - servers: 4 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + - servers: 4 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + - servers: 4 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + - servers: 4 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + credsSecret: + name: test-minio-creds-secret + diff --git a/testing/one-zone-multi-disk.yaml b/testing/one-zone-multi-disk.yaml new file mode 100644 index 00000000000..efbc24bc483 --- /dev/null +++ b/testing/one-zone-multi-disk.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-minio-creds-secret +type: Opaque +data: + accesskey: bWluaW8= # base 64 encoded "minio" (echo -n 'minio' | base64) + secretkey: bWluaW8xMjM= # based 64 encoded "minio123" (echo -n 'minio123' | base64) +--- +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-multi-disk +spec: + zones: + - servers: 1 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + credsSecret: + name: test-minio-creds-secret + diff --git a/testing/one-zone-multi-svc.yaml b/testing/one-zone-multi-svc.yaml new file mode 100644 index 00000000000..f4d96aecd38 --- /dev/null +++ b/testing/one-zone-multi-svc.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-minio-creds-secret +type: Opaque +data: + accesskey: bWluaW8= # base 64 encoded "minio" (echo -n 'minio' | base64) + secretkey: bWluaW8xMjM= # based 64 encoded "minio123" (echo -n 'minio123' | base64) +--- +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-multi-svc +spec: + zones: + - servers: 1 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + credsSecret: + name: test-minio-creds-secret + diff --git a/testing/one-zone-multi-svr.yaml b/testing/one-zone-multi-svr.yaml new file mode 100644 index 00000000000..53be1402f76 --- /dev/null +++ b/testing/one-zone-multi-svr.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-minio-creds-secret +type: Opaque +data: + accesskey: bWluaW8= # base 64 encoded "minio" (echo -n 'minio' | base64) + secretkey: bWluaW8xMjM= # based 64 encoded "minio123" (echo -n 'minio123' | base64) +--- +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-multi-svr +spec: + zones: + - servers: 2 + volumesPerServer: 2 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + credsSecret: + name: test-minio-creds-secret + diff --git a/testing/one-zone.yaml b/testing/one-zone.yaml new file mode 100644 index 00000000000..694f3b902b6 --- /dev/null +++ b/testing/one-zone.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-minio-creds-secret +type: Opaque +data: + accesskey: bWluaW8= # base 64 encoded "minio" (echo -n 'minio' | base64) + secretkey: bWluaW8xMjM= # based 64 encoded "minio123" (echo -n 'minio123' | base64) +--- +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + credsSecret: + name: test-minio-creds-secret + diff --git a/testing/two-zones.yaml b/testing/two-zones.yaml new file mode 100644 index 00000000000..38b102485a4 --- /dev/null +++ b/testing/two-zones.yaml @@ -0,0 +1,40 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-minio-creds-secret +type: Opaque +data: + accesskey: bWluaW8= # base 64 encoded "minio" (echo -n 'minio' | base64) + secretkey: bWluaW8xMjM= # based 64 encoded "minio123" (echo -n 'minio123' | base64) +--- +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: two-zones +spec: + zones: + - servers: 1 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + - servers: 1 + volumesPerServer: 4 + volumeClaimTemplate: + metadata: + name: data + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce + credsSecret: + name: test-minio-creds-secret + diff --git a/testing/validations/no-zones.yaml b/testing/validations/no-zones.yaml new file mode 100644 index 00000000000..6e0136c85a9 --- /dev/null +++ b/testing/validations/no-zones.yaml @@ -0,0 +1,4 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: no-zones diff --git a/testing/validations/one-zone-no-creds-secret.yaml b/testing/validations/one-zone-no-creds-secret.yaml new file mode 100644 index 00000000000..9dd2ab460fc --- /dev/null +++ b/testing/validations/one-zone-no-creds-secret.yaml @@ -0,0 +1,17 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-no-creds-secret +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + resources: + requests: + storage: 2Gi + accessModes: + - ReadWriteOnce diff --git a/testing/validations/one-zone-no-vct.yaml b/testing/validations/one-zone-no-vct.yaml new file mode 100644 index 00000000000..c15923eca8d --- /dev/null +++ b/testing/validations/one-zone-no-vct.yaml @@ -0,0 +1,9 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-no-vct +spec: + zones: + - servers: 1 + volumesPerServer: 1 + diff --git a/testing/validations/one-zone-vct-no-access-mode.yaml b/testing/validations/one-zone-vct-no-access-mode.yaml new file mode 100644 index 00000000000..86963eb128e --- /dev/null +++ b/testing/validations/one-zone-vct-no-access-mode.yaml @@ -0,0 +1,15 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-vct-no-access-mode +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + resources: + requests: + storage: 2Gi diff --git a/testing/validations/one-zone-vct-no-request.yaml b/testing/validations/one-zone-vct-no-request.yaml new file mode 100644 index 00000000000..4de6d1b3f36 --- /dev/null +++ b/testing/validations/one-zone-vct-no-request.yaml @@ -0,0 +1,12 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-vct-no-request +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + diff --git a/testing/validations/one-zone-vct-request-no-resources.yaml b/testing/validations/one-zone-vct-request-no-resources.yaml new file mode 100644 index 00000000000..9ce5c64cbe6 --- /dev/null +++ b/testing/validations/one-zone-vct-request-no-resources.yaml @@ -0,0 +1,16 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-vct-resources-no-storage +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + resources: + request: + cpu: 1.0 + diff --git a/testing/validations/one-zone-vct-resources-no-storage.yaml b/testing/validations/one-zone-vct-resources-no-storage.yaml new file mode 100644 index 00000000000..e69f7ef5088 --- /dev/null +++ b/testing/validations/one-zone-vct-resources-no-storage.yaml @@ -0,0 +1,15 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-vct-resources-no-storage +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + resources: + requests: + cpu: 1.0 diff --git a/testing/validations/one-zone-vct-resources-volume-2.yaml b/testing/validations/one-zone-vct-resources-volume-2.yaml new file mode 100644 index 00000000000..352b0067deb --- /dev/null +++ b/testing/validations/one-zone-vct-resources-volume-2.yaml @@ -0,0 +1,15 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-vct-resources-volume-2 +spec: + zones: + - servers: 1 + volumesPerServer: 2 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + resources: + requests: + storage: 0 diff --git a/testing/validations/one-zone-zero-servers.yaml b/testing/validations/one-zone-zero-servers.yaml new file mode 100644 index 00000000000..dbcf910d4de --- /dev/null +++ b/testing/validations/one-zone-zero-servers.yaml @@ -0,0 +1,8 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-zero-servers +spec: + zones: + - servers: 0 + diff --git a/testing/validations/one-zone-zero-volumes.yaml b/testing/validations/one-zone-zero-volumes.yaml new file mode 100644 index 00000000000..516a236726a --- /dev/null +++ b/testing/validations/one-zone-zero-volumes.yaml @@ -0,0 +1,9 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: one-zone-zero-volumes +spec: + zones: + - servers: 1 + volumesPerServer: 0 + diff --git a/testing/validations/two-zones-two-volumes-total.yaml b/testing/validations/two-zones-two-volumes-total.yaml new file mode 100644 index 00000000000..db56611d9f0 --- /dev/null +++ b/testing/validations/two-zones-two-volumes-total.yaml @@ -0,0 +1,28 @@ +apiVersion: minio.min.io/v1 +kind: Tenant +metadata: + name: two-zones-two-volumes-total +spec: + zones: + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - servers: 1 + volumesPerServer: 1 + volumeClaimTemplate: + metadata: + name: disk1 + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi