Skip to content

Commit

Permalink
Add kubectl-minio plugin (#188)
Browse files Browse the repository at this point in the history
  • Loading branch information
nitisht committed Aug 20, 2020
1 parent 3c1908d commit ea73bb4
Show file tree
Hide file tree
Showing 30 changed files with 4,609 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ minio-operator
!minio-operator/
.idea/
dist/
*.test
*.minisig
kubectl-minio/kubectl-minio
*.test*.minisig
16 changes: 15 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ GOPATH := $(shell go env GOPATH)
GOARCH := $(shell go env GOARCH)
GOOS := $(shell go env GOOS)

CRD_GEN_PATH=operator-kustomize/crds/
OPERATOR_YAML=./operator-kustomize/
TENANT_CRD=$(OPERATOR_YAML)crds/minio.min.io_tenants.yaml
PLUGIN_HOME=./kubectl-minio
PLUGIN_OPERATOR_YAML=$(PLUGIN_HOME)/static
PLUGIN_CRD_COPY=$(PLUGIN_OPERATOR_YAML)/crd.yaml
all: build

getdeps:
Expand Down Expand Up @@ -39,4 +45,12 @@ clean:
@find . -name '*~' | xargs rm -fv

regen-crd:
@controller-gen crd:trivialVersions=true paths="./..." output:crd:artifacts:config=operator-kustomize/crds/
@controller-gen crd:trivialVersions=true paths="./..." output:crd:artifacts:config=$(CRD_GEN_PATH)


plugin: regen-crd
@rm -rf $(PLUGIN_OPERATOR_YAML)
@mkdir -p $(PLUGIN_OPERATOR_YAML)
@cp $(TENANT_CRD) $(PLUGIN_CRD_COPY)
@cp $(OPERATOR_YAML)/*.yaml $(PLUGIN_OPERATOR_YAML)
@cd $(PLUGIN_HOME); go build -o kubectl-minio main.go
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/shirou/gopsutil v2.20.6+incompatible // indirect
github.com/stretchr/testify v1.4.0
k8s.io/api v0.18.6
k8s.io/apiextensions-apiserver v0.18.6 // indirect
k8s.io/apimachinery v0.18.6
k8s.io/client-go v0.18.6
k8s.io/klog/v2 v2.3.0
Expand Down
125 changes: 125 additions & 0 deletions go.sum

Large diffs are not rendered by default.

103 changes: 103 additions & 0 deletions kubectl-minio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# MinIO Kubectl Plugin

## Prerequisites

- Kubernetes >= v1.17.0.
- Create PVs using [direct CSI driver](https://github.com/minio/operator/blob/master/docs/using-direct-csi.md).
- kubectl installed on your local machine, configured to talk to the Kubernetes cluster.

## Install Plugin

Download the Kubectl plugin binary from [plugin release page](https://github.com/minio/operator/releases), and place the binary in executable path on your machine (e.g. `/usr/local/bin`).

## Plugin Commands

### Operator Deployment

Command: `kubectl minio operator create`

Creates MinIO Operator Deployment along with MinIO Tenant CRD, Service account, Cluster Role and Cluster Role Binding.

Options:

- `--image=minio/k8s-operator:3.0.5`
- `--namespace=minio-operator`
- `--service-account=minio-operator`
- `--cluster-domain=cluster.local`
- `--namespace-to-watch=default`
- `--image-pull-secret=`
- `--output`

### Tenant

#### MinIO Tenant Creation

Command: `kubectl minio tenant create --name TENANT_NAME --secret SECRET_NAME --servers SERVERS --volumes TOTAL_VOLUMES --capacity TOTAL_RAW_CAPACITY [options]`

Creates a MinIO Tenant based on the passed values.

example: `kubectl minio tenant create --name tenant1 --secret cred-secret --servers 4 --volumes 16 --capacity 16Ti`

Options:

- `--namespace=minio`
- `--image=minio/minio:RELEASE.2020-07-31T03-39-05Z`
- `--storageClass=local`
- `--kms-secret=secret-name`
- `--console-secret=secret-name`
- `--cert-secret=secret-name`
- `--image-pull-secret=`
- `--output`

#### Add Tenant Zones

Command: `kubectl minio tenant volumes add --name TENANT_NAME --servers SERVERS --volumes TOTAL_VOLUMES --capacity TOTAL_RAW_CAPACITY [options]`

Add new volumes (and nodes) to existing MinIO Tenant.

example: `kubectl minio tenant volumes add --name cluster1 --servers 4 --volumes 16 --capacity 16Ti`

Options:

- `--namespace=minio`
- `--storageClass=local`
- `--image-pull-secret=`
- `--output`

#### List Tenant Zones

Command: `kubectl minio tenant volumes list --name TENANT_NAME [options]`

List all existing MinIO Zones in the given MinIO Tenant.

example: `kubectl minio tenant volumes list --name cluster1`

Options:

- `--namespace=minio`

#### Upgrade Images

Command: `kubectl minio tenant upgrade --name TENANT_NAME --image IMAGE_TAG [options]`

Upgrade MinIO Docker image for the given MinIO Tenant.

example: `kubectl minio tenant upgrade --name cluster1 --image minio/minio:edge`

Options:

- `--namespace=minio`
- `--image-pull-secret=`
- `--output`

#### Remove Tenant

Command: `kubectl minio tenant delete --name TENANT_NAME [options]`

Delete an existing MinIO Tenant.

example: `kubectl minio tenant delete --name tenant1`

Options:

- `--namespace=minio`
185 changes: 185 additions & 0 deletions kubectl-minio/cmd/cmd-operator-create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* This file is part of MinIO Operator
* Copyright (C) 2020, MinIO, Inc.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

package cmd

import (
"context"
"errors"
"fmt"
"io"

"github.com/minio/kubectl-minio/cmd/helpers"
"github.com/minio/kubectl-minio/cmd/resources"
"github.com/spf13/cobra"

apiextensionv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextension "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
)

const (
operatorCreateDesc = `
'create' command creates MinIO Operator deployment along with all the dependencies.`
operatorCreateExample = ` kubectl minio operator create`
)

type operatorCreateCmd struct {
out io.Writer
errOut io.Writer
output bool
operatorOpts resources.OperatorOptions
steps []runtime.Object
}

func newOperatorCreateCmd(out io.Writer, errOut io.Writer) *cobra.Command {
o := &operatorCreateCmd{out: out, errOut: errOut}

cmd := &cobra.Command{
Use: "create",
Short: "Create MinIO Operator deployment",
Long: operatorCreateDesc,
Example: operatorCreateExample,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return errors.New("this command does not accept arguments")
}
return o.run()
},
}

f := cmd.Flags()
f.StringVarP(&o.operatorOpts.Image, "image", "i", helpers.DefaultOperatorImage, "operator image")
f.StringVarP(&o.operatorOpts.NS, "namespace", "n", helpers.DefaultNamespace, "namespace scope for this request")
f.StringVarP(&o.operatorOpts.ClusterDomain, "cluster-domain", "d", helpers.DefaultClusterDomain, "cluster domain of the Kubernetes cluster")
f.StringVar(&o.operatorOpts.ServiceAccount, "service-account", helpers.DefaultServiceAccount, "service account for operator")
f.StringVar(&o.operatorOpts.NSToWatch, "namespace-to-watch", "", "namespace where operator looks for MinIO tenants, leave empty for all namespaces")
f.StringVar(&o.operatorOpts.ImagePullSecret, "image-pull-secret", "", "image pull secret to be used for pulling operator image")
f.BoolVarP(&o.output, "output", "o", false, "dry run this command and generate requisite yaml")

return cmd
}

// run initializes local config and installs MinIO Operator to Kubernetes cluster.
func (o *operatorCreateCmd) run() error {
sa := resources.NewServiceAccountForOperator(o.operatorOpts.ServiceAccount, o.operatorOpts.NS)
crb := resources.NewCluterRoleBindingForOperator(o.operatorOpts.NS, o.operatorOpts.ServiceAccount)
d := resources.NewDeploymentForOperator(o.operatorOpts)

if !o.output {
client, err := helpers.GetKubeClient()
if err != nil {
return err
}
extclient, err := helpers.GetKubeExtensionClient()
if err != nil {
return err
}
if err = createCRD(extclient, crdObj); err != nil {
return err
}
if err = createCR(client, crObj); err != nil {
return err
}
if err = createSA(client, sa); err != nil {
return err
}
if err = createClusterRB(client, crb); err != nil {
return err
}
return createDeployment(client, d)
}

o.steps = append(o.steps, crdObj, crObj, sa, crb, d)
op, err := helpers.ToYaml(o.steps)
if err != nil {
return err
}
for _, s := range op {
fmt.Printf(s)
fmt.Println("---")
}
return nil
}

func createCRD(client *apiextension.Clientset, crd *apiextensionv1.CustomResourceDefinition) error {
_, err := client.ApiextensionsV1beta1().CustomResourceDefinitions().Create(context.Background(), crd, v1.CreateOptions{})
if err != nil {
if kerrors.IsAlreadyExists(err) {
return fmt.Errorf("CustomResourceDefinition %s: already present, skipped", crd.ObjectMeta.Name)
}
return err
}
fmt.Printf("CustomResourceDefinition %s: created\n", crd.ObjectMeta.Name)
return nil
}

func createCR(client *kubernetes.Clientset, cr *rbacv1.ClusterRole) error {
_, err := client.RbacV1().ClusterRoles().Create(context.Background(), cr, v1.CreateOptions{})
if err != nil {
if kerrors.IsAlreadyExists(err) {
return fmt.Errorf("ClusterRole %s: already present, skipped", cr.ObjectMeta.Name)
}
return err
}
fmt.Printf("ClusterRole %s: created\n", cr.ObjectMeta.Name)
return nil
}

func createSA(client *kubernetes.Clientset, sa *corev1.ServiceAccount) error {
_, err := client.CoreV1().ServiceAccounts(sa.ObjectMeta.Namespace).Create(context.Background(), sa, v1.CreateOptions{})
if err != nil {
if kerrors.IsAlreadyExists(err) {
return fmt.Errorf("ServiceAccount %s: already present, skipped", sa.ObjectMeta.Name)
}
return err
}
fmt.Printf("ServiceAccount %s: created\n", sa.ObjectMeta.Name)
return nil
}

func createClusterRB(client *kubernetes.Clientset, crb *rbacv1.ClusterRoleBinding) error {
_, err := client.RbacV1().ClusterRoleBindings().Create(context.Background(), crb, v1.CreateOptions{})
if err != nil {
if kerrors.IsAlreadyExists(err) {
return fmt.Errorf("ClusterRoleBinding %s: already present, skipped", crb.ObjectMeta.Name)
}
return err
}
fmt.Printf("ClusterRoleBinding %s: created\n", crb.ObjectMeta.Name)
return nil
}

func createDeployment(client *kubernetes.Clientset, d *appsv1.Deployment) error {
_, err := client.AppsV1().Deployments(d.ObjectMeta.Namespace).Create(context.Background(), d, v1.CreateOptions{})
if err != nil {
if kerrors.IsAlreadyExists(err) {
return fmt.Errorf("MinIO Operator Deployment %s: already present, skipped", d.ObjectMeta.Name)
}
return err
}
fmt.Printf("MinIO Operator Deployment %s: created\n", d.ObjectMeta.Name)
return nil
}
41 changes: 41 additions & 0 deletions kubectl-minio/cmd/cmd-operator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* This file is part of MinIO Operator
* Copyright (C) 2020, MinIO, Inc.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

package cmd

import (
"io"

"github.com/spf13/cobra"
)

const (
operatorDesc = `
'operator' is the top level command for managing MinIO operator.`
)

func newOperatorCmd(out io.Writer, errOut io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "operator",
Short: "Create MinIO operator",
Long: operatorDesc,
}

cmd.AddCommand(newOperatorCreateCmd(cmd.OutOrStdout(), cmd.ErrOrStderr()))
return cmd
}

0 comments on commit ea73bb4

Please sign in to comment.