Tuesday, 20 September 2016

Remote OpenStack Instances using Gophercloud (using neutron networking)

Remote OpenStack Instances using Gophercloud (using neutron networking)

Remote OpenStack Instances using Gophercloud (using neutron networking)

2020-03-16T22:24:21Z



Introduction:

Following program uses gophercloud library to spin instances in OpenStack environment. This program uses Neutron Networking. This program will also assign FloatingIP to very first instance.

Requirments:

An already running OpenStack environment. You can get a free playground for OpenStack to play with at http://trystack.org/. At minimum you need following information.

Auth URL : It may look like this http://10.0.2.15:5000/v2.0
UserName : This is a user in OpenStack. default: admin
Password : This is an API password. API password can be different from user password.
Tenant   : This is more like a project/Account or Organization. A tenant can have multiple users associated with it.. default: admin
Region   : Default region is set to RegionOne.

In trystack.org this information can be found at https://x86.trystack.org/dashboard/project/access_and_security/ and click on Download OpenStack RC file. Contents of RC file will have all the required information.

Following is the source code.

package main

import (
        "crypto/rand"
        "flag"
        "fmt"
        "github.com/rackspace/gophercloud"
        "github.com/rackspace/gophercloud/openstack"
        "github.com/rackspace/gophercloud/openstack/compute/v2/flavors"
        "github.com/rackspace/gophercloud/openstack/compute/v2/images"
        "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
        "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
        "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
        "github.com/rackspace/gophercloud/openstack/networking/v2/ports"
        "os"
        "strconv"
)

func checkErrorAndExit(err error) {
        if err != nil {
                fmt.Printf("Error: %v\n", err.Error())
                os.Exit(3)
        }
}

func checkErrorAndContinue(err error) {
        if err != nil {
                fmt.Printf("Error: %v\n", err.Error())
        }
}

func generateRandomString() string {
        b := make([]byte, 8)
        _, err := rand.Read(b)
        checkErrorAndExit(err)
        name := fmt.Sprintf("%X", b[0:4])
        return name
}

func main() {

        user := flag.String("user", "admin", "OS Username")
        pass := flag.String("password", "acf0d596fbb44b1d", "Password")
        authUrl := flag.String("authurl", "http://10.0.2.15:5000/v2.0", "AUTH URL")
        tenant := flag.String("tenant", "admin", "Tenant Name")
        region := flag.String("region", "RegionOne", "Region for VM")
        defaultRun := flag.Bool("runwithdefaultvalues", false, "Use this flag to use default values")
        image := flag.String("image", "cirros", "Image to be used")
        flavor := flag.String("flavor", "m1.tiny", "Size of VM")
        private_network := flag.String("private_network", "private", "private network for VM")
        public_network := flag.String("public_network", "public", "public network for VM")
        securityGroup := flag.String("securitygroup", "default", "Security Group for VM")

        hostNamePrefix := flag.String("hostnameprefix", generateRandomString(), "Hostname Prefix. default: randomly generated.")
        total := flag.String("total", "5", "Total number of instances")

        flag.Parse()

        os.Setenv("OS_USERNAME", *user)
        os.Setenv("OS_PASSWORD", *pass)
        os.Setenv("OS_AUTH_URL", *authUrl)
        os.Setenv("OS_TENANT_NAME", *tenant)
        os.Setenv("OS_REGION_NAME", *region)

        if flag.NFlag() == 0 {
                flag.PrintDefaults()
                os.Exit(1)
        } else if *defaultRun == true {
                fmt.Println("Creating VMs: ")
        } else {
                fmt.Println("Creating VMs: ")
        }

        authOpts, err := openstack.AuthOptionsFromEnv()
        checkErrorAndExit(err)

        provider, err := openstack.AuthenticatedClient(authOpts)
        checkErrorAndExit(err)

        otherOpts := gophercloud.EndpointOpts{Region: *region}
        client, err := openstack.NewComputeV2(provider, otherOpts)

        imageID, err := images.IDFromName(client, *image)
        checkErrorAndExit(err)

        flavorID, err := flavors.IDFromName(client, *flavor)
        checkErrorAndExit(err)

        netClient, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{Name: "neutron", Region: *region})
        checkErrorAndExit(err)

        privateNetworkID, err := networks.IDFromName(netClient, *private_network)
        checkErrorAndExit(err)

        publicNetworkID, err := networks.IDFromName(netClient, *public_network)
        checkErrorAndExit(err)

        portOpts := ports.CreateOpts{NetworkID: privateNetworkID,
                AdminStateUp: ports.Up}

        netport, err := ports.Create(netClient, portOpts).Extract()
        checkErrorAndExit(err)

        network1 := servers.Network{UUID: privateNetworkID}
        network2 := servers.Network{Port: netport.ID}

        allNetworks := []servers.Network{network1}
        allPortNetworks := []servers.Network{network2}

        fmt.Printf("Obtaining free floating IP: ")

        floatingIPOpts := floatingips.CreateOpts{FloatingNetworkID: publicNetworkID,
                PortID: netport.ID}

        floatingIP, err := floatingips.Create(netClient, floatingIPOpts).Extract()
        checkErrorAndExit(err)

        fmt.Printf("%s found.\n", floatingIP.FloatingIP)

        noOfInstances, err := strconv.Atoi(*total)
        checkErrorAndExit(err)

        for i := 1; i <= noOfInstances; i++ {
                networks := allNetworks
                if i == 1 {
                        networks = allPortNetworks
                } else {
                        networks = allNetworks
                }
                vmName := *hostNamePrefix + strconv.Itoa(i)
                serverCreateOpts := servers.CreateOpts{Name: vmName,
                        FlavorRef:      flavorID,
                        ImageRef:       imageID,
                        Networks:       networks,
                        UserData:       []byte{},
                        SecurityGroups: []string{*securityGroup}}

                _, err := servers.Create(client, serverCreateOpts).Extract()
                checkErrorAndContinue(err)
                fmt.Printf("%s VM creation request sent successfully.\n Details: { flavor=%s, image=%s, network=%s, sec_group=%s }\n", vmName, *flavor, *image, *private_network, *securityGroup)

                fmt.Println("===================================")
        }

}

Create a file launchOpenStackInstances.go and populate it with above contents. Use following steps on Linux and MacOS to compile/build it.

  • Make sure GO Lang compiler is installed.
  • Place go source code in a directory. (most likely home directory)
mkdir MYGO
export GOPATH=$HOME/MYGO
go get github.com/rackspace/gophercloud
go build launchOpenStackInstances.go
  • An executable with name launchOpenStackInstances will be there .

Below is the sample run:

# ./launchOpenStackInstances.go -authurl=http://10.1.0.10:5000/v2.0 -flavor=m1.tiny -image=cirros -private_network=private_network -public_network=public_network -user=admin -password=106d84bf40fb4413 -total=2
Creating VMs:
Obtaining free floating IP: 10.1.0.159 found.
5F52A0801 VM creation request sent successfully.
 Details: { flavor=m1.tiny, image=cirros, network=private_network, sec_group=default }
===================================
5F52A0802 VM creation request sent successfully.
 Details: { flavor=m1.tiny, image=cirros, network=private_network, sec_group=default }
===================================

Observation 1: This program uses Neutron Networking.

Observation 2: Compare this program with the program using Nova Networking. There is no infinite loop required to assign floatingIP in this program.

No comments:

Post a Comment