func TestServersCreateDestroy(t *testing.T) { client, err := clients.NewComputeV2Client() if err != nil { t.Fatalf("Unable to create a compute client: %v", err) } choices, err := clients.AcceptanceTestChoicesFromEnv() if err != nil { t.Fatal(err) } server, err := CreateServer(t, client, choices) if err != nil { t.Fatalf("Unable to create server: %v", err) } defer DeleteServer(t, client, server) newServer, err := servers.Get(client, server.ID).Extract() if err != nil { t.Errorf("Unable to retrieve server: %v", err) } PrintServer(t, newServer) allAddressPages, err := servers.ListAddresses(client, server.ID).AllPages() if err != nil { t.Errorf("Unable to list server addresses: %v", err) } allAddresses, err := servers.ExtractAddresses(allAddressPages) if err != nil { t.Errorf("Unable to extract server addresses: %v", err) } for network, address := range allAddresses { t.Logf("Addresses on %s: %+v", network, address) } allNetworkAddressPages, err := servers.ListAddressesByNetwork(client, server.ID, choices.NetworkName).AllPages() if err != nil { t.Errorf("Unable to list server addresses: %v", err) } allNetworkAddresses, err := servers.ExtractNetworkAddresses(allNetworkAddressPages) if err != nil { t.Errorf("Unable to extract server addresses: %v", err) } t.Logf("Addresses on %s:", choices.NetworkName) for _, address := range allNetworkAddresses { t.Logf("%+v", address) } }
func TestListAddressesByNetwork(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() HandleNetworkAddressListSuccessfully(t) expected := ListNetworkAddressesExpected pages := 0 err := servers.ListAddressesByNetwork(client.ServiceClient(), "asdfasdfasdf", "public").EachPage(func(page pagination.Page) (bool, error) { pages++ actual, err := servers.ExtractNetworkAddresses(page) th.AssertNoErr(t, err) if len(actual) != 2 { t.Fatalf("Expected 2 addresses, got %d", len(actual)) } th.CheckDeepEquals(t, expected, actual) return true, nil }) th.AssertNoErr(t, err) th.CheckEquals(t, 1, pages) }
// spawn achieves the aims of Spawn() func (p *openstackp) spawn(resources *Resources, osPrefix string, flavorID string, externalIP bool, postCreationScript []byte) (serverID string, serverIP string, adminPass string, err error) { // get available images, pick the one that matches desired OS // *** rackspace API lets you filter on eg. os_distro=ubuntu and os_version=12.04; can we do the same here? pager := images.ListDetail(p.computeClient, images.ListOpts{Status: "ACTIVE"}) var imageID string err = pager.EachPage(func(page pagination.Page) (bool, error) { imageList, err := images.ExtractImages(page) if err != nil { return false, err } for _, i := range imageList { if i.Progress == 100 && strings.HasPrefix(i.Name, osPrefix) { imageID = i.ID return false, nil } } return true, nil }) if err != nil { return } // create the server with a unique name server, err := servers.Create(p.computeClient, keypairs.CreateOptsExt{ CreateOptsBuilder: servers.CreateOpts{ Name: uniqueResourceName(resources.ResourceName), FlavorRef: flavorID, ImageRef: imageID, SecurityGroups: []string{p.securityGroup}, Networks: []servers.Network{{UUID: p.networkUUID}}, UserData: postCreationScript, // Metadata map[string]string }, KeyName: resources.ResourceName, }).Extract() if err != nil { return } // wait for it to come up; servers.WaitForStatus has a timeout, but it // doesn't always work, so we roll our own waitForActive := make(chan error) go func() { timeout := time.After(60 * time.Second) ticker := time.NewTicker(1 * time.Second) for { select { case <-ticker.C: current, err := servers.Get(p.computeClient, server.ID).Extract() if err != nil { ticker.Stop() waitForActive <- err return } if current.Status == "ACTIVE" { ticker.Stop() waitForActive <- nil return } if current.Status == "ERROR" { ticker.Stop() waitForActive <- errors.New("there was an error in bringing up the new server") return } continue case <-timeout: ticker.Stop() waitForActive <- errors.New("timed out waiting for server to become ACTIVE") return } } }() err = <-waitForActive if err != nil { // since we're going to return an error that we failed to spawn, try and // delete the bad server in case it is still there servers.Delete(p.computeClient, server.ID) return } // *** NB. it can still take some number of seconds before I can ssh to it serverID = server.ID adminPass = server.AdminPass // get the servers IP; if we error for any reason we'll delete the server // first, because without an IP it's useless if externalIP { // give it a floating ip var floatingIP string floatingIP, err = p.getAvailableFloatingIP() if err != nil { p.destroyServer(serverID) return } // associate floating ip with server *** we have a race condition // between finding/creating free floating IP above, and using it here err = floatingips.AssociateInstance(p.computeClient, serverID, floatingips.AssociateOpts{ FloatingIP: floatingIP, }).ExtractErr() if err != nil { p.destroyServer(serverID) return } serverIP = floatingIP } else { // find its auto-assigned internal ip *** there must be a better way of // doing this... allNetworkAddressPages, serr := servers.ListAddressesByNetwork(p.computeClient, serverID, p.networkName).AllPages() if serr != nil { p.destroyServer(serverID) err = serr return } allNetworkAddresses, serr := servers.ExtractNetworkAddresses(allNetworkAddressPages) if serr != nil { p.destroyServer(serverID) err = serr return } for _, address := range allNetworkAddresses { if address.Version == 4 && strings.HasPrefix(address.Address, "192.168") { serverIP = address.Address break } } } return }