Skip to content

Commit

Permalink
feat(migrate): add support for CR status reporting (#65)
Browse files Browse the repository at this point in the history
Signed-off-by: shubham <[email protected]>
  • Loading branch information
shubham14bajpai authored Nov 5, 2020
1 parent f92acb0 commit fd566a8
Show file tree
Hide file tree
Showing 10 changed files with 684 additions and 39 deletions.
143 changes: 143 additions & 0 deletions ci/migrate/migrationCRD.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Copyright © 2020 The OpenEBS Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
creationTimestamp: null
name: migrationtasks.openebs.io
spec:
group: openebs.io
names:
kind: MigrationTask
listKind: MigrationTaskList
plural: migrationtasks
shortNames:
- mtask
singular: migrationtask
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: MigrationTask represents an migration task
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: Spec i.e. specifications of the MigrationTask
properties:
cstorPool:
description: MigrateCStorPool contains the details of the cstor pool
to be migrated
properties:
rename:
description: If a CSPC with the same name as SPC already exists
then we can rename SPC during migration using Rename
type: string
spcName:
description: SPCName contains the name of the storage pool claim
to be migrated
type: string
type: object
cstorVolume:
description: MigrateCStorVolume contains the details of the cstor
volume to be migrated
properties:
pvName:
description: PVName contains the name of the pv associated with
the cstor volume to be migrated
type: string
type: object
type: object
status:
description: Status of MigrationTask
properties:
completedTime:
description: CompletedTime of Migrate
format: date-time
nullable: true
type: string
migrationDetailedStatuses:
description: MigrationDetailedStatuses contains the list of statuses
of each step
items:
description: MigrationDetailedStatuses represents the latest available
observations of a MigrationTask current state.
properties:
lastUpdatedAt:
description: LastUpdatedTime of a MigrateStep
format: date-time
nullable: true
type: string
message:
description: A human-readable message indicating details about
why the migrationStep is in this state
type: string
phase:
description: Phase indicates if the MigrateStep is waiting,
errored or completed.
type: string
reason:
description: Reason is a brief CamelCase string that describes
any failure and is meant for machine parsing and tidy display
in the CLI
type: string
startTime:
description: StartTime of a MigrateStep
format: date-time
nullable: true
type: string
step:
type: string
type: object
type: array
phase:
description: Phase indicates if a migrationTask is started, success
or errored
type: string
retries:
description: Retries is the number of times the job attempted to migration
the resource
type: integer
startTime:
description: StartTime of Migrate
format: date-time
nullable: true
type: string
type: object
required:
- spec
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
1 change: 1 addition & 0 deletions ci/migrate/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ kubectl wait --for=condition=Ready pod -l lkey=lvalue --timeout=600s

echo "Install cstor & csi operators"

kubectl apply -f ./ci/migrate/migrationCRD.yaml
kubectl apply -f https://raw.githubusercontent.com/openebs/charts/gh-pages/cstor-operator.yaml
sleep 5

Expand Down
1 change: 1 addition & 0 deletions cmd/migrate/executor/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type MigrateOptions struct {
spcName string
cspcName string
pvName string
resourceKind string
}

var (
Expand Down
182 changes: 182 additions & 0 deletions cmd/migrate/executor/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
Copyright 2020 The OpenEBS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package executor

import (
"os"
"strings"

"k8s.io/client-go/rest"

v1Alpha1API "github.com/openebs/api/v2/pkg/apis/openebs.io/v1alpha1"
openebsclientset "github.com/openebs/api/v2/pkg/client/clientset/versioned"
"github.com/openebs/maya/pkg/util"
cmdUtil "github.com/openebs/upgrade/cmd/util"
migrate "github.com/openebs/upgrade/pkg/migrate/cstor"
errors "github.com/pkg/errors"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

var (
resourceMigrateCmdHelpText = `
This command migrates the resource mentioned in the MigrationTask CR.
The name of the MigrationTask CR is extracted from the ENV UPGRADE_TASK
Usage: migrate resource
`
)

// ResourceOptions stores information required for migrationTask migrate
type ResourceOptions struct {
name string
}

// NewMigrateResourceJob migrate a resource from migrationTask
func NewMigrateResourceJob() *cobra.Command {
cmd := &cobra.Command{
Use: "resource",
Short: "Migrate a resource using the details specified in the MigrationTask CR.",
Long: resourceMigrateCmdHelpText,
Example: `migrate resource`,
Run: func(cmd *cobra.Command, args []string) {
client, err := initClient()
util.CheckErr(err, util.Fatal)
name := args[0]
openebsNamespace := cmdUtil.GetOpenEBSNamespace()
migrationTaskObj, err := client.OpenebsV1alpha1().
MigrationTasks(openebsNamespace).
Get(name, metav1.GetOptions{})
util.CheckErr(err, util.Fatal)
util.CheckErr(options.InitializeFromMigrationTaskResource(migrationTaskObj), util.Fatal)
util.CheckErr(options.RunPreFlightChecks(), util.Fatal)
err = options.RunResourceMigrate()
if err != nil {
migrationTaskObj, uerr := client.OpenebsV1alpha1().MigrationTasks(openebsNamespace).
Get(name, metav1.GetOptions{})
if uerr != nil {
util.Fatal(uerr.Error())
}
backoffLimit, uerr := getBackoffLimit(openebsNamespace)
if uerr != nil {
util.Fatal(uerr.Error())
}
migrationTaskObj.Status.Retries = migrationTaskObj.Status.Retries + 1
if migrationTaskObj.Status.Retries == backoffLimit {
migrationTaskObj.Status.Phase = v1Alpha1API.MigrateError
migrationTaskObj.Status.CompletedTime = metav1.Now()
}
_, uerr = client.OpenebsV1alpha1().MigrationTasks(openebsNamespace).
Update(migrationTaskObj)
if uerr != nil {
util.Fatal(uerr.Error())
}
util.Fatal(err.Error())
} else {
migrationTaskObj, uerr := client.OpenebsV1alpha1().MigrationTasks(openebsNamespace).
Get(name, metav1.GetOptions{})
if uerr != nil {
util.Fatal(uerr.Error())
}
migrationTaskObj.Status.Phase = v1Alpha1API.MigrateSuccess
migrationTaskObj.Status.CompletedTime = metav1.Now()
_, uerr = client.OpenebsV1alpha1().MigrationTasks(openebsNamespace).
Update(migrationTaskObj)
if uerr != nil {
util.Fatal(uerr.Error())
}
}
},
}
return cmd
}

// InitializeFromMigrationTaskResource will populate the MigrateOptions from given MigrationTask
func (m *MigrateOptions) InitializeFromMigrationTaskResource(
migrationTaskObj *v1Alpha1API.MigrationTask) error {

if len(strings.TrimSpace(m.openebsNamespace)) == 0 {
return errors.Errorf("Cannot execute migrate job: namespace is missing")
}

switch {
case migrationTaskObj.Spec.MigrateResource.MigrateCStorPool != nil:
m.resourceKind = "storagePoolClaim"
m.spcName = migrationTaskObj.Spec.MigrateCStorPool.SPCName
m.cspcName = migrationTaskObj.Spec.MigrateCStorPool.Rename

case migrationTaskObj.Spec.MigrateResource.MigrateCStorVolume != nil:
m.resourceKind = "cstorVolume"
m.pvName = migrationTaskObj.Spec.MigrateCStorVolume.PVName
}

return nil
}

// RunResourceMigrate migrates the given migrationTask
func (m *MigrateOptions) RunResourceMigrate() error {
migrate.IsMigrationTaskJob = true
var err error
switch m.resourceKind {
case "storagePoolClaim":
err = m.RunCStorSPCMigrate()
case "cstorVolume":
err = m.RunCStorVolumeMigrate()
}
return err
}

func initClient() (openebsclientset.Interface, error) {
cfg, err := rest.InClusterConfig()
if err != nil {
return nil, errors.Wrap(err, "error building kubeconfig")
}
client, err := openebsclientset.NewForConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "error building openebs clientset")
}
return client, nil
}

func getBackoffLimit(openebsNamespace string) (int, error) {
cfg, err := rest.InClusterConfig()
if err != nil {
return 0, errors.Wrap(err, "error building kubeconfig")
}
client, err := kubernetes.NewForConfig(cfg)
if err != nil {
return 0, errors.Wrap(err, "error building openebs clientset")
}
podName := os.Getenv("POD_NAME")
podObj, err := client.CoreV1().Pods(openebsNamespace).
Get(podName, metav1.GetOptions{})
if err != nil {
return 0, errors.Wrapf(err, "failed to get backoff limit")
}
jobObj, err := client.BatchV1().Jobs(openebsNamespace).
Get(podObj.OwnerReferences[0].Name, metav1.GetOptions{})
if err != nil {
return 0, errors.Wrapf(err, "failed to get backoff limit")
}
// if backoffLimit not present it returns the default as 6
if jobObj.Spec.BackoffLimit == nil {
return 6, nil
}
backoffLimit := int(*jobObj.Spec.BackoffLimit)
return backoffLimit, nil
}
1 change: 1 addition & 0 deletions cmd/migrate/executor/setup_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func NewJob() *cobra.Command {
cmd.AddCommand(
NewMigratePoolJob(),
NewMigrateCStorVolumeJob(),
NewMigrateResourceJob(),
)

cmd.PersistentFlags().StringVarP(&options.openebsNamespace,
Expand Down
3 changes: 3 additions & 0 deletions pkg/migrate/cstor/blockdevice_correction.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ func (c *CSPCMigrator) updateBDRefsAndlabels(spcObj *apis.StoragePoolClaim, oldB
retryBDCStatus:
newBDCObj, err = c.OpenebsClientset.OpenebsV1alpha1().
BlockDeviceClaims(c.OpenebsNamespace).Get(newBDCObj.Name, metav1.GetOptions{})
if err != nil {
return err
}
if newBDCObj.Status.Phase != v1alpha1.BlockDeviceClaimStatusDone {
klog.Infof("waiting for bd %s to get bound", newBDObj.Name)
time.Sleep(2 * time.Second)
Expand Down
8 changes: 8 additions & 0 deletions pkg/migrate/cstor/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ limitations under the License.

package migrate

var (
// IsMigrationTaskJob is used to determine
// whether to report the utask errors. Errors
// are reported only when job is triggered by
// the resource command.
IsMigrationTaskJob = false
)

// Migrator abstracts the migration of a resource
type Migrator interface {
Migrate(name, namespace string) error
Expand Down
Loading

0 comments on commit fd566a8

Please sign in to comment.