Commit 49e011ea authored by GLYASAI's avatar GLYASAI
Browse files

grctl upgrade cluster

Showing with 380 additions and 1 deletion
+380 -1
......@@ -27,6 +27,7 @@ import (
"github.com/goodrain/rainbond/builder/sources"
k8sutil "github.com/goodrain/rainbond/util/k8s"
"github.com/sirupsen/logrus"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
......@@ -42,6 +43,7 @@ var (
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(rainbondv1alpha1.AddToScheme(scheme))
utilruntime.Must(apiextensionsv1beta1.AddToScheme(scheme))
}
//K8SClient K8SClient
......
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2021 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cluster
import (
"context"
"fmt"
"strings"
"github.com/docker/distribution/reference"
"github.com/goodrain/rainbond-operator/api/v1alpha1"
"github.com/goodrain/rainbond/grctl/clients"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/yaml"
)
// Cluster represents a rainbond cluster.
type Cluster struct {
rainbondCluster *v1alpha1.RainbondCluster
namespace string
newVersion string
}
// NewCluster creates new cluster.
func NewCluster(namespace, newVersion string) (*Cluster, error) {
rainbondCluster, err := getRainbondCluster(namespace)
if err != nil {
return nil, err
}
return &Cluster{
rainbondCluster: rainbondCluster,
namespace: namespace,
newVersion: newVersion,
}, nil
}
// Upgrade upgrade cluster.
func (c *Cluster) Upgrade() error {
logrus.Infof("upgrade cluster from %s to %s", c.rainbondCluster.Spec.InstallVersion, c.newVersion)
if errs := c.createCrds(); len(errs) > 0 {
return errors.New(strings.Join(errs, ","))
}
if errs := c.updateRbdComponents(); len(errs) > 0 {
return fmt.Errorf("update rainbond components: %s", strings.Join(errs, ","))
}
if err := c.updateCluster(); err != nil {
return err
}
return nil
}
func (c *Cluster) createCrds() []string {
crds, err := c.getCrds()
if err != nil {
return []string{err.Error()}
}
logrus.Info("start creating crds")
var errs []string
for _, crd := range crds {
if err := c.createCrd(crd); err != nil {
errs = append(errs, err.Error())
}
}
logrus.Info("crds created")
return errs
}
func (c *Cluster) createCrd(crdStr string) error {
var crd apiextensionsv1beta1.CustomResourceDefinition
if err := yaml.Unmarshal([]byte(crdStr), &crd); err != nil {
return fmt.Errorf("unmarshal crd: %v", err)
}
if err := clients.RainbondKubeClient.Create(context.Background(), &crd); err != nil {
return fmt.Errorf("create crd: %v", err)
}
return nil
}
func (c *Cluster) getCrds() ([]string, error) {
key := c.rainbondCluster.Spec.InstallVersion + "-" + c.newVersion
logrus.Infof("key: %s", key)
version, ok := versions[key]
if !ok {
return nil, fmt.Errorf("unsupport new version %s", c.newVersion)
}
return version.CRDs, nil
}
func (c *Cluster) updateRbdComponents() []string {
componentNames := []string{
"rbd-api",
"rbd-chaos",
"rbd-mq",
"rbd-eventlog",
"rbd-gateway",
"rbd-node",
"rbd-resource-proxy",
"rbd-webcli",
"rbd-worker",
}
var errs []string
for _, name := range componentNames {
err := c.updateRbdComponent(name)
if err != nil {
errs = append(errs, err.Error())
}
}
return errs
}
func (c *Cluster) updateRbdComponent(name string) error {
var cpt v1alpha1.RbdComponent
err := clients.RainbondKubeClient.Get(context.Background(),
types.NamespacedName{Namespace: c.namespace, Name: name}, &cpt)
if err != nil {
return fmt.Errorf("get rbdcomponent %s: %v", name, err)
}
ref, err := reference.Parse(cpt.Spec.Image)
if err != nil {
return fmt.Errorf("parse image %s: %v", cpt.Spec.Image, err)
}
repo := ref.(reference.Named)
newImage := repo.Name() + ":" + c.newVersion
oldImageName := cpt.Spec.Image
cpt.Spec.Image = newImage
if err := clients.RainbondKubeClient.Update(context.Background(), &cpt); err != nil {
return fmt.Errorf("update rbdcomponent %s: %v", name, err)
}
logrus.Infof("update rbdcomponent %s \nfrom %s \nto %s", name, oldImageName, newImage)
return nil
}
func (c *Cluster) updateCluster() error {
c.rainbondCluster.Spec.InstallVersion = c.newVersion
if err := clients.RainbondKubeClient.Update(context.Background(), c.rainbondCluster); err != nil {
return fmt.Errorf("update rainbond cluster: %v", err)
}
logrus.Infof("update rainbond cluster to %s", c.newVersion)
return nil
}
func getRainbondCluster(namespace string) (*v1alpha1.RainbondCluster, error) {
var cluster v1alpha1.RainbondCluster
err := clients.RainbondKubeClient.Get(context.Background(),
types.NamespacedName{Namespace: namespace, Name: "rainbondcluster"}, &cluster)
if err != nil {
return nil, fmt.Errorf("get rainbond cluster: %v", err)
}
return &cluster, nil
}
package cluster
var versions = map[string]Version{
"v5.3.0-release-v5.3.1-release": {
CRDs: []string{
helmappCRD531,
},
},
}
type Version struct {
CRDs []string
}
var helmappCRD531 = `
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.2.5
creationTimestamp: null
name: helmapps.rainbond.goodrain.io
spec:
group: rainbond.goodrain.io
names:
kind: HelmApp
listKind: HelmAppList
plural: helmapps
singular: helmapp
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: HelmApp -
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: HelmAppSpec defines the desired state of HelmApp
properties:
appStore:
description: The helm app store.
properties:
branch:
description: The branch of a git repo.
type: string
name:
description: The name of app store.
type: string
password:
description: The chart repository password where to locate the requested
chart
type: string
url:
description: The url of helm repo, sholud be a helm native repo
url or a git url.
type: string
username:
description: The chart repository username where to locate the requested
chart
type: string
version:
description: The verision of the helm app store.
type: string
required:
- name
- url
- version
type: object
eid:
type: string
overrides:
description: Overrides will overrides the values in the chart.
items:
type: string
type: array
preStatus:
description: The prerequisite status.
enum:
- NotConfigured
- Configured
type: string
revision:
description: The application revision.
type: integer
templateName:
description: The application name.
type: string
version:
description: The application version.
type: string
required:
- appStore
- eid
- templateName
- version
type: object
status:
description: HelmAppStatus defines the observed state of HelmApp
properties:
conditions:
description: Current state of helm app.
items:
description: HelmAppCondition contains details for the current condition
of this helm application.
properties:
lastTransitionTime:
description: Last time the condition transitioned from one status
to another.
format: date-time
type: string
message:
description: Human-readable message indicating details about last
transition.
type: string
reason:
description: Unique, one-word, CamelCase reason for the condition's
last transition.
type: string
status:
description: 'Status is the status of the condition. Can be True,
False, Unknown. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions'
type: string
type:
description: Type is the type of the condition.
type: string
required:
- status
- type
type: object
type: array
currentVersion:
description: The version infect.
type: string
overrides:
description: Overrides in effect.
items:
type: string
type: array
phase:
description: The phase of the helm app.
type: string
status:
description: The status of helm app.
type: string
required:
- phase
- status
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
`
......@@ -28,6 +28,7 @@ import (
rainbondv1alpha1 "github.com/goodrain/rainbond-operator/api/v1alpha1"
"github.com/goodrain/rainbond/grctl/clients"
"github.com/goodrain/rainbond/grctl/cluster"
"github.com/goodrain/rainbond/node/nodem/client"
"github.com/goodrain/rainbond/util/termtables"
"github.com/gosuri/uitable"
......@@ -42,7 +43,7 @@ func NewCmdCluster() cli.Command {
Name: "cluster",
Usage: "show curren cluster datacenter info",
Subcommands: []cli.Command{
cli.Command{
{
Name: "config",
Usage: "prints the current cluster configuration",
Flags: []cli.Flag{
......@@ -57,6 +58,30 @@ func NewCmdCluster() cli.Command {
return printConfig(c)
},
},
{
Name: "upgrade",
Usage: "upgrade cluster",
Flags: []cli.Flag{
cli.StringFlag{
Name: "namespace, ns",
Usage: "rainbond default namespace",
Value: "rbd-system",
},
cli.StringFlag{
Name: "new-version",
Usage: "the new version of rainbond cluster",
Required: true,
},
},
Action: func(c *cli.Context) error {
Common(c)
cluster, err := cluster.NewCluster(c.String("namespace"), c.String("new-version"))
if err != nil {
return err
}
return cluster.Upgrade()
},
},
},
Flags: []cli.Flag{
cli.StringFlag{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment