pkg

package
v0.1.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2020 License: Apache-2.0 Imports: 47 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ImageCmd = &cobra.Command{
	Use:   "image <name|id>",
	Args:  cobra.ExactArgs(1),
	Short: "Clone an image",
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if err := parseTimeoutArgs(); err != nil {
			return err
		}
		return viper.BindPFlags(cmd.Flags())
	},
	RunE: func(cmd *cobra.Command, args []string) error {

		image := args[0]
		toName := viper.GetString("to-image-name")

		loc, err := getSrcAndDst("")
		if err != nil {
			return err
		}

		srcProvider, err := NewOpenStackClient(loc.Src)
		if err != nil {
			return fmt.Errorf("failed to create a source OpenStack client: %s", err)
		}

		srcImageClient, err := NewGlanceV2Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source image client: %s", err)
		}

		srcObjectClient, err := NewObjectStorageV1Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source object storage client: %s", err)
		}

		if v, err := images_utils.IDFromName(srcImageClient, image); err == nil {
			image = v
		}

		dstProvider, err := NewOpenStackClient(loc.Dst)
		if err != nil {
			return fmt.Errorf("failed to create a destination OpenStack client: %s", err)
		}

		dstImageClient, err := NewGlanceV2Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination image client: %s", err)
		}

		srcImg, err := waitForImage(srcImageClient, image, waitForImageSec)
		if err != nil {
			return fmt.Errorf("failed to wait for %q source image: %s", image, err)
		}

		defer measureTime()

		_, err = migrateImage(srcImageClient, dstImageClient, srcObjectClient, srcImg, toName)

		return err
	},
}

ImageCmd represents the image command

View Source
var RootCmd = &cobra.Command{
	Use:          "cyclone",
	Short:        "Clone OpenStack entities easily",
	SilenceUsage: true,
}

RootCmd represents the base command when called without any subcommands

View Source
var ServerCmd = &cobra.Command{
	Use:   "server <name|id>",
	Args:  cobra.ExactArgs(1),
	Short: "Clone a server",
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if err := parseTimeoutArgs(); err != nil {
			return err
		}
		return viper.BindPFlags(cmd.Flags())
	},
	RunE: func(cmd *cobra.Command, args []string) error {

		server := args[0]
		toName := viper.GetString("to-server-name")
		toKeyName := viper.GetString("to-key-name")
		toFlavor := viper.GetString("to-flavor-name")
		toNetworkName := viper.GetString("to-network-name")
		toSubnetName := viper.GetString("to-subnet-name")
		toAZ := viper.GetString("to-az")
		cloneViaSnapshot := viper.GetBool("clone-via-snapshot")
		forceBootable := viper.GetUint("bootable-volume")

		loc, err := getSrcAndDst(toAZ)
		if err != nil {
			return err
		}

		srcProvider, err := NewOpenStackClient(loc.Src)
		if err != nil {
			return fmt.Errorf("failed to create a source OpenStack client: %s", err)
		}

		srcServerClient, err := NewComputeV2Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source server client: %s", err)
		}

		srcImageClient, err := NewGlanceV2Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source image client: %s", err)
		}

		srcObjectClient, err := NewObjectStorageV1Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source object storage client: %s", err)
		}

		srcVolumeClient, err := NewBlockStorageV3Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source volume client: %s", err)
		}

		if v, err := servers_utils.IDFromName(srcServerClient, server); err == nil {
			server = v
		}

		dstProvider, err := NewOpenStackClient(loc.Dst)
		if err != nil {
			return fmt.Errorf("failed to create a destination OpenStack client: %s", err)
		}

		dstServerClient, err := NewComputeV2Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination server client: %s", err)
		}

		dstImageClient, err := NewGlanceV2Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination image client: %s", err)
		}

		dstVolumeClient, err := NewBlockStorageV3Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination volume client: %s", err)
		}

		dstNetworkClient, err := NewNetworkV2Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination network client: %s", err)
		}

		srcServer, err := waitForServer(srcServerClient, server, waitForServerSec)
		if err != nil {
			return fmt.Errorf("failed to wait for %q source server: %s", server, err)
		}

		srcFlavor, err := getSrcFlavor(srcServerClient, srcServer)
		if err != nil {
			return err
		}
		flavorID, err := checkFlavor(dstServerClient, srcFlavor, &toFlavor)
		if err != nil {
			return err
		}

		err = checkAvailabilityZone(dstServerClient, srcServer.AvailabilityZone, &toAZ, &loc)
		if err != nil {
			return err
		}

		err = checKeyPair(dstServerClient, toKeyName)
		if err != nil {
			return err
		}

		// check destination network, create a port for a server
		var port *ports.Port
		var networkID string
		var network servers.Network

		if toSubnetName != "" {

			port, err = createServerPort(dstNetworkClient, toNetworkName, toSubnetName)
			if err != nil {
				return err
			}
			network.Port = port.ID
			defer func() {
				if err != nil {

					if err := ports.Delete(dstNetworkClient, port.ID).ExtractErr(); err != nil {
						log.Printf("Error deleting target server port: %s", err)
					}
				}
			}()
		} else {
			networkID, err = networks_utils.IDFromName(dstNetworkClient, toNetworkName)
			if err != nil {
				return err
			}
			network.UUID = networkID
		}

		defer measureTime()

		var vols []string
		var bootableVolume bool
		vols, bootableVolume, err = serverVolumeAttachments(srcServerClient, srcServer)
		if err != nil {
			return fmt.Errorf("failed to detect server volume attachments: %s", err)
		}

		log.Printf("Detected %q attached volumes", vols)

		var dstVolumes []*volumes.Volume
		var dstImage *images.Image
		if bootableVolume {
			log.Printf("The %q volume is a bootable volume", vols[0])
		} else {
			if forceBootable > 0 && uint(srcFlavor.Disk) > forceBootable {
				return fmt.Errorf("cannot create a bootable volume with a size less than original disk size: %d", srcFlavor.Disk)
			}

			dstImage, err = createServerSnapshot(srcServerClient, srcImageClient, dstImageClient, srcObjectClient, srcServer, loc)
			if err != nil {
				return err
			}

			dstImageID := dstImage.ID
			defer func() {
				if err := images.Delete(dstImageClient, dstImageID).ExtractErr(); err != nil {
					log.Printf("Error deleting migrated server snapshot: %s", err)
				}
			}()

			if forceBootable > 0 {
				if uint(srcFlavor.Disk) > forceBootable {
					return fmt.Errorf("cannot create a bootable volume with a size less than original disk size: %d", srcFlavor.Disk)
				}
				log.Printf("Forcing %s image to be converted to a bootable volume", dstImageID)
				bootableVolume = true
				var newBootableVolume *volumes.Volume
				newBootableVolume, err = imageToVolume(dstVolumeClient, dstImageClient, dstImage.ID, fmt.Sprintf("bootable for %s", dstImage.Name), "", toAZ, int(forceBootable))
				if err != nil {
					return fmt.Errorf("failed to create a bootable volume for a VM", err)
				}
				dstVolumes = append(dstVolumes, newBootableVolume)

				dstImage = nil
			}
		}

		for i, v := range vols {
			var srcVolume, dstVolume *volumes.Volume
			srcVolume, err = waitForVolume(srcVolumeClient, v, waitForVolumeSec)
			if err != nil {
				return fmt.Errorf("failed to wait for a %q volume: %s", v, err)
			}

			dstVolume, err = migrateVolume(srcImageClient, srcVolumeClient, srcObjectClient, dstImageClient, dstVolumeClient, srcVolume, srcVolume.Name, toAZ, cloneViaSnapshot, loc)
			if err != nil {

				return fmt.Errorf("failed to clone the %q volume: %s", srcVolume.ID, err)
			}

			dstVolumes = append(dstVolumes, dstVolume)

			if toAZ == "" {
				toAZ = dstVolumes[i].AvailabilityZone
			}

		}

		createOpts := createServerOpts(srcServer, toName, flavorID, toKeyName, toAZ, network, dstVolumes, dstImage, bootableVolume)
		dstServer := new(serverExtended)
		err = servers.Create(dstServerClient, createOpts).ExtractInto(dstServer)
		if err != nil {
			return fmt.Errorf("failed to create a destination server: %s", err)
		}

		dstServer, err = waitForServer(dstServerClient, dstServer.ID, waitForServerSec)
		if err != nil {

			retErr := fmt.Errorf("failed to wait for %q target server: %s", dstServer.ID, err)
			err = nil
			return retErr
		}

		createServerSpeed(dstServer)

		if dstImage != nil {

			if _, err := waitForImage(dstImageClient, dstImage.ID, waitForImageSec); err != nil {
				log.Printf("Error waiting for %q image: %s", dstImage.ID, err)
			}
		}

		log.Printf("Server cloned to %q (%q) using %s flavor to %q availability zone", dstServer.Name, dstServer.ID, toFlavor, dstServer.AvailabilityZone)
		if port != nil {
			log.Printf("The %q port in the %q subnet was created", port.ID, toSubnetName)
		}

		return err
	},
}

ServerCmd represents the server command

View Source
var Version = "dev"
View Source
var VersionCmd = &cobra.Command{
	Use:               "version",
	Short:             "Print version information",
	DisableAutoGenTag: true,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("cyclone %s compiled with %v on %v/%v\n",
			Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
	},
}
View Source
var VolumeCmd = &cobra.Command{
	Use:   "volume <name|id>",
	Args:  cobra.ExactArgs(1),
	Short: "Clone a volume",
	PreRunE: func(cmd *cobra.Command, args []string) error {
		if err := parseTimeoutArgs(); err != nil {
			return err
		}
		return viper.BindPFlags(cmd.Flags())
	},
	RunE: func(cmd *cobra.Command, args []string) error {

		volume := args[0]

		toAZ := viper.GetString("to-az")
		toName := viper.GetString("to-volume-name")
		cloneViaSnapshot := viper.GetBool("clone-via-snapshot")

		loc, err := getSrcAndDst(toAZ)
		if err != nil {
			return err
		}

		srcProvider, err := NewOpenStackClient(loc.Src)
		if err != nil {
			return fmt.Errorf("failed to create a source OpenStack client: %s", err)
		}

		srcImageClient, err := NewGlanceV2Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source image client: %s", err)
		}

		srcVolumeClient, err := NewBlockStorageV3Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source volume client: %s", err)
		}

		srcObjectClient, err := NewObjectStorageV1Client(srcProvider, loc.Src.Region)
		if err != nil {
			return fmt.Errorf("failed to create source object storage client: %s", err)
		}

		if v, err := volumes_utils.IDFromName(srcVolumeClient, volume); err == nil {
			volume = v
		}

		dstProvider, err := NewOpenStackClient(loc.Dst)
		if err != nil {
			return fmt.Errorf("failed to create a destination OpenStack client: %s", err)
		}

		dstImageClient, err := NewGlanceV2Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination image client: %s", err)
		}

		dstVolumeClient, err := NewBlockStorageV3Client(dstProvider, loc.Dst.Region)
		if err != nil {
			return fmt.Errorf("failed to create destination volume client: %s", err)
		}

		srcVolume, err := waitForVolume(srcVolumeClient, volume, waitForVolumeSec)
		if err != nil {
			return fmt.Errorf("failed to wait for a %q volume: %s", volume, err)
		}

		err = checkAvailabilityZone(dstVolumeClient, srcVolume.AvailabilityZone, &toAZ, &loc)
		if err != nil {
			return err
		}

		defer measureTime()

		dstVolume, err := migrateVolume(srcImageClient, srcVolumeClient, srcObjectClient, dstImageClient, dstVolumeClient, srcVolume, toName, toAZ, cloneViaSnapshot, loc)
		if err != nil {
			return err
		}

		log.Printf("Migrated target volume name is %q (id: %q) to %q availability zone", dstVolume.Name, dstVolume.ID, dstVolume.AvailabilityZone)

		return nil
	},
}

VolumeCmd represents the volume command

Functions

func Execute

func Execute()

Execute adds all child commands to the root command sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd.

func NewBlockStorageV3Client

func NewBlockStorageV3Client(provider *gophercloud.ProviderClient, region string) (*gophercloud.ServiceClient, error)

func NewComputeV2Client

func NewComputeV2Client(provider *gophercloud.ProviderClient, region string) (*gophercloud.ServiceClient, error)

func NewGlanceV2Client

func NewGlanceV2Client(provider *gophercloud.ProviderClient, region string) (*gophercloud.ServiceClient, error)

func NewNetworkV2Client

func NewNetworkV2Client(provider *gophercloud.ProviderClient, region string) (*gophercloud.ServiceClient, error)

func NewObjectStorageV1Client

func NewObjectStorageV1Client(provider *gophercloud.ProviderClient, region string) (*gophercloud.ServiceClient, error)

func NewOpenStackClient

func NewOpenStackClient(loc Location) (*gophercloud.ProviderClient, error)

Types

type Location

type Location struct {
	AuthURL                     string
	Region                      string
	Domain                      string
	Project                     string
	Username                    string
	Password                    string
	ApplicationCredentialName   string
	ApplicationCredentialID     string
	ApplicationCredentialSecret string
	Origin                      string
}

type Locations

type Locations struct {
	Src         Location
	Dst         Location
	SameRegion  bool
	SameAZ      bool
	SameProject bool
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
JackTT - Gopher 🇻🇳