From 7d2633a11688a803c0d3b7e27d394b34cfc1dcef Mon Sep 17 00:00:00 2001 From: Dimitris Moraitis Date: Sun, 27 Oct 2019 19:38:31 +0000 Subject: [PATCH] Add tests for Packet cloudprovider --- .../cloudprovider/packet/packet_manager.go | 1 + .../packet/packet_manager_rest.go | 63 +++++++---- .../packet/packet_manager_rest_test.go | 79 ++++++++++++++ .../cloudprovider/packet/packet_node_group.go | 10 +- .../packet/packet_node_group_test.go | 100 ++++++++++++++++++ 5 files changed, 226 insertions(+), 27 deletions(-) create mode 100644 cluster-autoscaler/cloudprovider/packet/packet_manager_rest_test.go create mode 100644 cluster-autoscaler/cloudprovider/packet/packet_node_group_test.go diff --git a/cluster-autoscaler/cloudprovider/packet/packet_manager.go b/cluster-autoscaler/cloudprovider/packet/packet_manager.go index 46f532cc09e..9e083cb1964 100644 --- a/cluster-autoscaler/cloudprovider/packet/packet_manager.go +++ b/cluster-autoscaler/cloudprovider/packet/packet_manager.go @@ -43,6 +43,7 @@ type packetManager interface { nodeGroupSize(nodegroup string) (int, error) createNodes(nodegroup string, nodes int) error getNodes(nodegroup string) ([]string, error) + getNodeNames(nodegroup string) ([]string, error) deleteNodes(nodegroup string, nodes []NodeRef, updatedNodeCount int) error templateNodeInfo(nodegroup string) (*schedulernodeinfo.NodeInfo, error) } diff --git a/cluster-autoscaler/cloudprovider/packet/packet_manager_rest.go b/cluster-autoscaler/cloudprovider/packet/packet_manager_rest.go index a89bfe5a83e..6ccbdd1352c 100644 --- a/cluster-autoscaler/cloudprovider/packet/packet_manager_rest.go +++ b/cluster-autoscaler/cloudprovider/packet/packet_manager_rest.go @@ -38,6 +38,7 @@ import ( ) type packetManagerRest struct { + baseURL string clusterName string projectID string apiServerEndpoint string @@ -160,6 +161,7 @@ func createPacketManagerRest(configReader io.Reader, discoverOpts cloudprovider. } manager := packetManagerRest{ + baseURL: "https://api.packet.net", clusterName: cfg.Global.ClusterName, projectID: cfg.Global.ProjectID, apiServerEndpoint: cfg.Global.APIServerEndpoint, @@ -174,10 +176,10 @@ func createPacketManagerRest(configReader io.Reader, discoverOpts cloudprovider. return &manager, nil } -func (mgr *packetManagerRest) listPacketDevices() *Devices { +func (mgr *packetManagerRest) listPacketDevices() (*Devices, error) { var jsonStr = []byte(``) packetAuthToken := os.Getenv("PACKET_AUTH_TOKEN") - url := "https://api.packet.net/projects/" + mgr.projectID + "/devices" + url := mgr.baseURL + "/projects/" + mgr.projectID + "/devices" req, _ := http.NewRequest("GET", url, bytes.NewBuffer(jsonStr)) req.Header.Set("X-Auth-Token", packetAuthToken) req.Header.Set("Content-Type", "application/json") @@ -189,16 +191,22 @@ func (mgr *packetManagerRest) listPacketDevices() *Devices { } defer resp.Body.Close() - fmt.Println("response Status:", resp.Status) - body, _ := ioutil.ReadAll(resp.Body) + klog.Infof("response Status: %s", resp.Status) + var devices Devices - json.Unmarshal([]byte(body), &devices) - return &devices + + if "200 OK" == resp.Status { + body, _ := ioutil.ReadAll(resp.Body) + json.Unmarshal([]byte(body), &devices) + return &devices, nil + } + + return &devices, fmt.Errorf(resp.Status, resp.Body) } // nodeGroupSize gets the current size of the nodegroup as reported by packet tags. func (mgr *packetManagerRest) nodeGroupSize(nodegroup string) (int, error) { - devices := mgr.listPacketDevices() + devices, _ := mgr.listPacketDevices() // Get the count of devices tagged as nodegroup members count := 0 for _, d := range devices.Devices { @@ -206,7 +214,7 @@ func (mgr *packetManagerRest) nodeGroupSize(nodegroup string) (int, error) { count++ } } - fmt.Println(len(devices.Devices), count) + klog.V(3).Infof("Nodegroup %s: %d/%d", nodegroup, count, len(devices.Devices)) return count, nil } @@ -252,13 +260,13 @@ func (mgr *packetManagerRest) createNode(cloudinit, nodegroup string) { HardwareReservationID: reservation, } - resp, err := createDevice(&cr) + resp, err := createDevice(&cr, mgr.baseURL) if err != nil || resp.StatusCode > 299 { // If reservation is preferred but not available, retry provisioning as on-demand if reservation != "" && mgr.reservation == "prefer" { klog.Infof("Reservation preferred but not available. Provisioning on-demand node.") cr.HardwareReservationID = "" - resp, err = createDevice(&cr) + resp, err = createDevice(&cr, mgr.baseURL) if err != nil { klog.Errorf("Failed to create device using Packet API: %v", err) panic(err) @@ -304,9 +312,9 @@ func (mgr *packetManagerRest) createNodes(nodegroup string, nodes int) error { return nil } -func createDevice(cr *DeviceCreateRequest) (*http.Response, error) { +func createDevice(cr *DeviceCreateRequest, baseURL string) (*http.Response, error) { packetAuthToken := os.Getenv("PACKET_AUTH_TOKEN") - url := "https://api.packet.net/projects/" + cr.ProjectID + "/devices" + url := baseURL + "/projects/" + cr.ProjectID + "/devices" jsonValue, _ := json.Marshal(cr) klog.Infof("Creating new node") klog.V(3).Infof("POST %s \n%v", url, string(jsonValue)) @@ -325,18 +333,37 @@ func createDevice(cr *DeviceCreateRequest) (*http.Response, error) { // getNodes should return ProviderIDs for all nodes in the node group, // used to find any nodes which are unregistered in kubernetes. func (mgr *packetManagerRest) getNodes(nodegroup string) ([]string, error) { - // TODO: get node ProviderIDs by getting device IDs from Packet - // This works fine being empty for now anyway. - return []string{}, nil + // Get node ProviderIDs by getting device IDs from Packet + devices, err := mgr.listPacketDevices() + nodes := []string{} + for _, d := range devices.Devices { + if Contains(d.Tags, "k8s-cluster-"+mgr.clusterName) && Contains(d.Tags, "k8s-nodepool-"+nodegroup) { + nodes = append(nodes, d.ID) + } + } + return nodes, err +} + +// getNodeNames should return Names for all nodes in the node group, +// used to find any nodes which are unregistered in kubernetes. +func (mgr *packetManagerRest) getNodeNames(nodegroup string) ([]string, error) { + devices, err := mgr.listPacketDevices() + nodes := []string{} + for _, d := range devices.Devices { + if Contains(d.Tags, "k8s-cluster-"+mgr.clusterName) && Contains(d.Tags, "k8s-nodepool-"+nodegroup) { + nodes = append(nodes, d.Hostname) + } + } + return nodes, err } // deleteNodes deletes nodes by passing a comma separated list of names or IPs func (mgr *packetManagerRest) deleteNodes(nodegroup string, nodes []NodeRef, updatedNodeCount int) error { - klog.Infof("Deleting nodes") + klog.Infof("Deleting nodes %v", nodes) packetAuthToken := os.Getenv("PACKET_AUTH_TOKEN") for _, n := range nodes { klog.Infof("Node %s - %s - %s", n.Name, n.MachineID, n.IPs) - dl := mgr.listPacketDevices() + dl, _ := mgr.listPacketDevices() klog.Infof("%d devices total", len(dl.Devices)) // Get the count of devices tagged as nodegroup for _, d := range dl.Devices { @@ -345,7 +372,7 @@ func (mgr *packetManagerRest) deleteNodes(nodegroup string, nodes []NodeRef, upd klog.Infof("nodegroup match %s %s", d.Hostname, n.Name) if d.Hostname == n.Name { klog.V(1).Infof("Matching Packet Device %s - %s", d.Hostname, d.ID) - req, _ := http.NewRequest("DELETE", "https://api.packet.net/devices/"+d.ID, bytes.NewBuffer([]byte(""))) + req, _ := http.NewRequest("DELETE", mgr.baseURL+"/devices/"+d.ID, bytes.NewBuffer([]byte(""))) req.Header.Set("X-Auth-Token", packetAuthToken) req.Header.Set("Content-Type", "application/json") diff --git a/cluster-autoscaler/cloudprovider/packet/packet_manager_rest_test.go b/cluster-autoscaler/cloudprovider/packet/packet_manager_rest_test.go new file mode 100644 index 00000000000..ea9eb19625f --- /dev/null +++ b/cluster-autoscaler/cloudprovider/packet/packet_manager_rest_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2019 The Kubernetes 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 packet + +import ( + // "fmt" + + // "strings" + + "os" + "testing" + + . "k8s.io/autoscaler/cluster-autoscaler/utils/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +const listPacketDevicesResponse = ` +{"devices":[{"id":"4d47a322-47e6-40cc-8402-e22b9933fb8f","short_id":"4d47a322","hostname":"k8s-worker-1","description":null,"state":"active","tags":["k8s-nodepool-pool1","k8s-cluster-cluster1"],"image_url":null,"billing_cycle":"hourly","user":"root","iqn":"iqn.2019-05.net.packet:device.4d47a322","locked":false,"bonding_mode":5,"created_at":"2019-05-24T11:59:52Z","updated_at":"2019-08-22T14:45:27Z","ipxe_script_url":null,"always_pxe":false,"storage":{},"customdata":{},"operating_system":{"id":"201bc259-982b-41a1-a4c1-bba01ce71f51","slug":"ubuntu_18_04","name":"Ubuntu 18.04 LTS","distro":"ubuntu","version":"18.04","provisionable_on":["baremetal_2a4","baremetal_2a5","c1.bloomberg.x86","c1.large.arm","baremetal_2a","c1.large.arm.xda","baremetal_2a2","c1.small.x86","baremetal_1","c1.xlarge.x86","baremetal_3","c2.large.anbox","c2.large.arm","c2.medium.x86","c2.small.x86","c3.medium.x86","c3.medium.x86","cpe1.c1.r720xd","cpe1.c1.r720xd","cpe1.g1.4028gr","cpe1.g1.4028gr","cpe1.m2.r640","cpe1.m2.r640","cpe1.s1.r730","cpe1.s1.r730","d1f.optane.x86","d1p.optane.x86","g2.large.x86","m1.xlarge.x86","baremetal_2","m2.xlarge.x86","n2.xlarge.x86","s1.large.x86","baremetal_s","t1.small.x86","baremetal_0","x1.small.x86","baremetal_1e","x2.graphcore.x86","x2.xlarge.x86"],"preinstallable":false,"pricing":{},"licensed":false},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"project":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"ssh_keys":[{"href":"/ssh-keys/1fd6e5a9-966d-4937-89b2-e269ff1d447a"},{"href":"/ssh-keys/22f9fd4c-ab3d-47f5-92ac-7d5703084d3d"},{"href":"/ssh-keys/23640808-0983-4b5c-b251-2f7715f5450a"},{"href":"/ssh-keys/2af51313-c514-4145-907f-f7445ca2e5ad"}],"project_lite":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"volumes":[],"ip_addresses":[{"id":"d06ebdf8-57d1-4b07-974d-c23c013901b7","address_family":4,"netmask":"255.255.255.254","created_at":"2019-05-24T11:59:55Z","details":null,"tags":[],"public":true,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/4d47a322-47e6-40cc-8402-e22b9933fb8f"},"interface":{"href":"/ports/283fb58f-eacc-4f21-818e-619029b859aa"},"network":"147.75.85.136","address":"147.75.85.137","gateway":"147.75.85.136","href":"/ips/d06ebdf8-57d1-4b07-974d-c23c013901b7"},{"id":"31466841-6877-4197-966d-80125b8bf2a0","address_family":4,"netmask":"255.255.255.240","created_at":"2019-05-24T11:59:55Z","details":null,"tags":[],"public":false,"cidr":28,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/4d47a322-47e6-40cc-8402-e22b9933fb8f"},"interface":{"href":"/ports/283fb58f-eacc-4f21-818e-619029b859aa"},"network":"10.80.125.144","address":"10.80.125.146","gateway":"10.80.125.145","href":"/ips/31466841-6877-4197-966d-80125b8bf2a0"}],"created_by":{"id":"bd4f24f3-33f0-46a6-9528-4e31e2ba6074","full_name":"Dimitris Moraitis","avatar_thumb_url":"https://www.gravatar.com/avatar/702119decab6288093449009ab5af843?d=mm","email":"dimo@mist.io"},"plan":{"id":"e69c0169-4726-46ea-98f1-939c9e8a3607","slug":"baremetal_0","name":"t1.small.x86","description":"Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.","line":"baremetal","specs":{"cpus":[{"count":1,"type":"Intel Atom C2550 @ 2.4Ghz"}],"memory":{"total":"8GB"},"drives":[{"count":1,"size":"80GB","type":"SSD"}],"nics":[{"count":2,"type":"1Gbps"}],"features":{"raid":false,"txt":true}},"legacy":false,"deployment_types":["on_demand","spot_market"],"available_in":[{"href":"/facilities/8e6470b3-b75e-47d1-bb93-45b225750975"},{"href":"/facilities/2b70eb8f-fa18-47c0-aba7-222a842362fd"},{"href":"/facilities/8ea03255-89f9-4e62-9d3f-8817db82ceed"},{"href":"/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09"}],"class":"t1.small.x86","pricing":{"hour":0.07}},"userdata":"","switch_uuid":"a7994efc","network_ports":[{"id":"283fb58f-eacc-4f21-818e-619029b859aa","type":"NetworkBondPort","name":"bond0","data":{"bonded":true},"network_type":"layer3","native_virtual_network":null,"hardware":{"href":"/hardware/6c6046ef-df41-4c04-8522-69e4ec798024"},"virtual_networks":[],"connected_port":null,"href":"/ports/283fb58f-eacc-4f21-818e-619029b859aa"},{"id":"c0dcccb1-0c57-4be6-970a-3589cbb34355","type":"NetworkPort","name":"eth0","data":{"mac":"0c:c4:7a:e5:42:ce","bonded":true},"bond":{"id":"283fb58f-eacc-4f21-818e-619029b859aa","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/6c6046ef-df41-4c04-8522-69e4ec798024"},"virtual_networks":[],"connected_port":{"href":"/ports/57412b1f-f1fd-4071-8db2-5bc6494b9438"},"href":"/ports/c0dcccb1-0c57-4be6-970a-3589cbb34355"},{"id":"8fb7496b-32c1-45f4-8120-4b8faeaa57c3","type":"NetworkPort","name":"eth1","data":{"mac":"0c:c4:7a:e5:42:cf","bonded":true},"bond":{"id":"283fb58f-eacc-4f21-818e-619029b859aa","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/6c6046ef-df41-4c04-8522-69e4ec798024"},"virtual_networks":[],"connected_port":{"href":"/ports/d0803efe-50e7-492b-9044-b3ce9af609cc"},"href":"/ports/8fb7496b-32c1-45f4-8120-4b8faeaa57c3"}],"href":"/devices/4d47a322-47e6-40cc-8402-e22b9933fb8f"},{"id":"8a56bcad-e26f-4b0d-8d46-f490917ab2a3","short_id":"8a56bcad","hostname":"k8s-master-1","description":null,"state":"active","tags":["k8s-cluster-cluster1"],"image_url":null,"billing_cycle":"hourly","user":"root","iqn":"iqn.2019-05.net.packet:device.8a56bcad","locked":false,"bonding_mode":5,"created_at":"2019-05-24T11:59:51Z","updated_at":"2019-08-22T14:33:00Z","ipxe_script_url":null,"always_pxe":false,"storage":{},"customdata":{},"operating_system":{"id":"201bc259-982b-41a1-a4c1-bba01ce71f51","slug":"ubuntu_18_04","name":"Ubuntu 18.04 LTS","distro":"ubuntu","version":"18.04","provisionable_on":["baremetal_2a4","baremetal_2a5","c1.bloomberg.x86","c1.large.arm","baremetal_2a","c1.large.arm.xda","baremetal_2a2","c1.small.x86","baremetal_1","c1.xlarge.x86","baremetal_3","c2.large.anbox","c2.large.arm","c2.medium.x86","c2.small.x86","c3.medium.x86","c3.medium.x86","cpe1.c1.r720xd","cpe1.c1.r720xd","cpe1.g1.4028gr","cpe1.g1.4028gr","cpe1.m2.r640","cpe1.m2.r640","cpe1.s1.r730","cpe1.s1.r730","d1f.optane.x86","d1p.optane.x86","g2.large.x86","m1.xlarge.x86","baremetal_2","m2.xlarge.x86","n2.xlarge.x86","s1.large.x86","baremetal_s","t1.small.x86","baremetal_0","x1.small.x86","baremetal_1e","x2.graphcore.x86","x2.xlarge.x86"],"preinstallable":false,"pricing":{},"licensed":false},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"project":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"ssh_keys":[{"href":"/ssh-keys/1fd6e5a9-966d-4937-89b2-e269ff1d447a"}],"project_lite":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"volumes":[],"ip_addresses":[{"id":"f77aa56c-a781-441d-bb40-c639db16a3cc","address_family":4,"netmask":"255.255.255.254","created_at":"2019-05-24T11:59:54Z","details":null,"tags":[],"public":true,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/8a56bcad-e26f-4b0d-8d46-f490917ab2a3"},"interface":{"href":"/ports/51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1"},"network":"147.75.102.14","address":"147.75.102.15","gateway":"147.75.102.14","href":"/ips/f77aa56c-a781-441d-bb40-c639db16a3cc"},{"id":"24502d6d-a633-4650-9650-6c9d3de50b72","address_family":4,"netmask":"255.255.255.240","created_at":"2019-05-24T11:59:54Z","details":null,"tags":[],"public":false,"cidr":28,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/8a56bcad-e26f-4b0d-8d46-f490917ab2a3"},"interface":{"href":"/ports/51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1"},"network":"10.80.125.128","address":"10.80.125.130","gateway":"10.80.125.129","href":"/ips/24502d6d-a633-4650-9650-6c9d3de50b72"}],"created_by":{"id":"bd4f24f3-33f0-46a6-9528-4e31e2ba6074","full_name":"Dimitris Moraitis","avatar_thumb_url":"https://www.gravatar.com/avatar/702119decab6288093449009ab5af843?d=mm","email":"dimo@mist.io"},"plan":{"id":"e69c0169-4726-46ea-98f1-939c9e8a3607","slug":"baremetal_0","name":"t1.small.x86","description":"Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.","line":"baremetal","specs":{"cpus":[{"count":1,"type":"Intel Atom C2550 @ 2.4Ghz"}],"memory":{"total":"8GB"},"drives":[{"count":1,"size":"80GB","type":"SSD"}],"nics":[{"count":2,"type":"1Gbps"}],"features":{"raid":false,"txt":true}},"legacy":false,"deployment_types":["on_demand","spot_market"],"available_in":[{"href":"/facilities/8e6470b3-b75e-47d1-bb93-45b225750975"},{"href":"/facilities/2b70eb8f-fa18-47c0-aba7-222a842362fd"},{"href":"/facilities/8ea03255-89f9-4e62-9d3f-8817db82ceed"},{"href":"/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09"}],"class":"t1.small.x86","pricing":{"hour":0.07}},"userdata":"","switch_uuid":"ddb086ff","network_ports":[{"id":"51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1","type":"NetworkBondPort","name":"bond0","data":{"bonded":true},"network_type":"layer3","native_virtual_network":null,"hardware":{"href":"/hardware/7f262628-7db2-4b4b-90b1-41529818c7c0"},"virtual_networks":[],"connected_port":null,"href":"/ports/51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1"},{"id":"2281afe5-c934-407a-abe0-b1f315291d3d","type":"NetworkPort","name":"eth0","data":{"mac":"0c:c4:7a:e5:43:04","bonded":true},"bond":{"id":"51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/7f262628-7db2-4b4b-90b1-41529818c7c0"},"virtual_networks":[],"connected_port":{"href":"/ports/cba6a9dd-550d-4e11-a93c-3a7b83bfaa65"},"href":"/ports/2281afe5-c934-407a-abe0-b1f315291d3d"},{"id":"1f351695-103b-4d92-9c7e-a6ce03904b12","type":"NetworkPort","name":"eth1","data":{"mac":"0c:c4:7a:e5:43:05","bonded":true},"bond":{"id":"51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/7f262628-7db2-4b4b-90b1-41529818c7c0"},"virtual_networks":[],"connected_port":{"href":"/ports/c7466539-f5c6-41b9-9bb2-97490d6b7c10"},"href":"/ports/1f351695-103b-4d92-9c7e-a6ce03904b12"}],"href":"/devices/8a56bcad-e26f-4b0d-8d46-f490917ab2a3"}],"meta":{"first":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df/devices?page=1"},"previous":null,"self":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df/devices?page=1"},"next":null,"last":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df/devices?page=1"},"current_page":1,"last_page":1,"total":2}}` + +const listPacketDevicesResponseAfterCreate = ` +{"devices":[{"id":"55de9631-b5a2-4e2b-82e5-3c8eff5af12a","short_id":"55de9631","hostname":"k8s-cluster1-pool1-vaxicfgl","description":null,"state":"active","tags":["k8s-cluster-cluster1","k8s-nodepool-pool1"],"image_url":null,"billing_cycle":"hourly","user":"root","iqn":"iqn.2019-10.net.packet:device.55de9631","locked":false,"bonding_mode":5,"created_at":"2019-10-18T23:58:13Z","updated_at":"2019-10-19T00:01:40Z","ipxe_script_url":null,"always_pxe":false,"storage":null,"customdata":{},"operating_system":{"id":"201bc259-982b-41a1-a4c1-bba01ce71f51","slug":"ubuntu_18_04","name":"Ubuntu 18.04 LTS","distro":"ubuntu","version":"18.04","provisionable_on":["baremetal_2a4","baremetal_2a5","c1.bloomberg.x86","c1.large.arm","baremetal_2a","c1.large.arm.xda","baremetal_2a2","c1.small.x86","baremetal_1","c1.xlarge.x86","baremetal_3","c2.large.anbox","c2.large.arm","c2.medium.x86","c2.small.x86","c3.medium.x86","c3.medium.x86","cpe1.c1.r720xd","cpe1.c1.r720xd","cpe1.g1.4028gr","cpe1.g1.4028gr","cpe1.m2.r640","cpe1.m2.r640","cpe1.s1.r730","cpe1.s1.r730","d1f.optane.x86","d1p.optane.x86","g2.large.x86","m1.xlarge.x86","baremetal_2","m2.xlarge.x86","n2.xlarge.x86","s1.large.x86","baremetal_s","t1.small.x86","baremetal_0","x1.small.x86","baremetal_1e","x2.graphcore.x86","x2.xlarge.x86"],"preinstallable":false,"pricing":{},"licensed":false},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"project":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"ssh_keys":[{"href":"/ssh-keys/cf8abbdd-a484-43c3-ba62-627a16594594"},{"href":"/ssh-keys/502178f5-b985-466b-980e-f01ba028e5fc"},{"href":"/ssh-keys/2b38c95c-02dc-4ce8-961c-9d2ce8763647"}],"project_lite":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"volumes":[],"ip_addresses":[{"id":"ba847802-bfaf-49e2-b9f5-c4389fd41512","address_family":4,"netmask":"255.255.255.254","created_at":"2019-10-18T23:58:16Z","details":null,"tags":[],"public":true,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/55de9631-b5a2-4e2b-82e5-3c8eff5af12a"},"interface":{"href":"/ports/5df5872e-7e29-43d7-9903-cba7bdca5d68"},"network":"147.75.101.4","address":"147.75.101.5","gateway":"147.75.101.4","href":"/ips/ba847802-bfaf-49e2-b9f5-c4389fd41512"},{"id":"14a3b5ab-9755-4290-8b09-63d8a5004078","address_family":6,"netmask":"ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe","created_at":"2019-10-18T23:58:16Z","details":null,"tags":[],"public":true,"cidr":127,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/55de9631-b5a2-4e2b-82e5-3c8eff5af12a"},"interface":{"href":"/ports/5df5872e-7e29-43d7-9903-cba7bdca5d68"},"network":"2604:1380:2000:ec00::2","address":"2604:1380:2000:ec00::3","gateway":"2604:1380:2000:ec00::2","href":"/ips/14a3b5ab-9755-4290-8b09-63d8a5004078"},{"id":"906cf79a-4138-4321-853a-7bf7b92c0c00","address_family":4,"netmask":"255.255.255.254","created_at":"2019-10-18T23:58:16Z","details":null,"tags":[],"public":false,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/55de9631-b5a2-4e2b-82e5-3c8eff5af12a"},"interface":{"href":"/ports/5df5872e-7e29-43d7-9903-cba7bdca5d68"},"network":"10.80.84.138","address":"10.80.84.139","gateway":"10.80.84.138","href":"/ips/906cf79a-4138-4321-853a-7bf7b92c0c00"}],"created_by":{"id":"446476b8-a835-414a-8e9c-84925cc72705","full_name":"Markos Gogoulos","avatar_thumb_url":"https://www.gravatar.com/avatar/fafa2cd3f9d378981e87a993661859b4?d=mm","email":"mgogoulos@mist.io"},"plan":{"id":"e69c0169-4726-46ea-98f1-939c9e8a3607","slug":"t1.small.x86","name":"t1.small.x86","description":"Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.","line":"baremetal","specs":{"cpus":[{"count":1,"type":"Intel Atom C2550 @ 2.4Ghz"}],"memory":{"total":"8GB"},"drives":[{"count":1,"size":"80GB","type":"SSD"}],"nics":[{"count":2,"type":"1Gbps"}],"features":{"raid":false,"txt":true}},"legacy":false,"deployment_types":["on_demand","spot_market"],"available_in":[{"href":"/facilities/8e6470b3-b75e-47d1-bb93-45b225750975"},{"href":"/facilities/2b70eb8f-fa18-47c0-aba7-222a842362fd"},{"href":"/facilities/8ea03255-89f9-4e62-9d3f-8817db82ceed"},{"href":"/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09"}],"class":"t1.small.x86","pricing":{"hour":0.07}},"userdata":"#!/bin/bash\nexport DEBIAN_FRONTEND=noninteractive\napt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -\ncurl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -\ncat </etc/apt/sources.list.d/kubernetes.list\ndeb https://apt.kubernetes.io/ kubernetes-xenial main\nEOF\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\"\napt-get update\napt-get upgrade -y\napt-get install -y kubelet kubeadm kubectl\napt-mark hold kubelet kubeadm kubectl\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable\"\napt update\napt install -y docker-ce=18.06.2~ce~3-0~ubuntu\ncat > /etc/docker/daemon.json < /etc/fstab\nkubeadm join --discovery-token-unsafe-skip-ca-verification --token 07401b.f395accd246ae52d 147.75.102.15:6443\n","root_password":"NCp5)m0%7-","switch_uuid":"a7994efc","network_ports":[{"id":"5df5872e-7e29-43d7-9903-cba7bdca5d68","type":"NetworkBondPort","name":"bond0","data":{"bonded":true},"network_type":"layer3","native_virtual_network":null,"hardware":{"href":"/hardware/9e88d670-8a26-43e2-aef7-7963924832ed"},"virtual_networks":[],"connected_port":null,"href":"/ports/5df5872e-7e29-43d7-9903-cba7bdca5d68"},{"id":"926abcab-4bb1-42a9-9f8a-5dc1536a2c26","type":"NetworkPort","name":"eth0","data":{"mac":"0c:c4:7a:e5:44:ca","bonded":true},"bond":{"id":"5df5872e-7e29-43d7-9903-cba7bdca5d68","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/9e88d670-8a26-43e2-aef7-7963924832ed"},"virtual_networks":[],"connected_port":{"href":"/ports/083133e8-62a7-4434-a91d-dea9f33b2569"},"href":"/ports/926abcab-4bb1-42a9-9f8a-5dc1536a2c26"},{"id":"8d5fe47b-1e11-4fee-a661-b559c21b3c0a","type":"NetworkPort","name":"eth1","data":{"mac":"0c:c4:7a:e5:44:cb","bonded":true},"bond":{"id":"5df5872e-7e29-43d7-9903-cba7bdca5d68","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/9e88d670-8a26-43e2-aef7-7963924832ed"},"virtual_networks":[],"connected_port":{"href":"/ports/12dc62ac-96a8-487e-b5a2-eb45038797fc"},"href":"/ports/8d5fe47b-1e11-4fee-a661-b559c21b3c0a"}],"href":"/devices/55de9631-b5a2-4e2b-82e5-3c8eff5af12a"},{"id":"a40d063e-2513-4c1e-a48e-1cafbab436e3","short_id":"a40d063e","hostname":"k8s-cluster1-pool1-ztrxjzao","description":null,"state":"active","tags":["k8s-cluster-cluster1","k8s-nodepool-pool1"],"image_url":null,"billing_cycle":"hourly","user":"root","iqn":"iqn.2019-10.net.packet:device.a40d063e","locked":false,"bonding_mode":5,"created_at":"2019-10-18T23:58:09Z","updated_at":"2019-10-19T00:04:27Z","ipxe_script_url":null,"always_pxe":false,"storage":null,"customdata":{},"hardware_reservation":{"href":"/hardware-reservations/28d695ad-243e-4cba-9e90-cc55b880bc69"},"operating_system":{"id":"201bc259-982b-41a1-a4c1-bba01ce71f51","slug":"ubuntu_18_04","name":"Ubuntu 18.04 LTS","distro":"ubuntu","version":"18.04","provisionable_on":["baremetal_2a4","baremetal_2a5","c1.bloomberg.x86","c1.large.arm","baremetal_2a","c1.large.arm.xda","baremetal_2a2","c1.small.x86","baremetal_1","c1.xlarge.x86","baremetal_3","c2.large.anbox","c2.large.arm","c2.medium.x86","c2.small.x86","c3.medium.x86","c3.medium.x86","cpe1.c1.r720xd","cpe1.c1.r720xd","cpe1.g1.4028gr","cpe1.g1.4028gr","cpe1.m2.r640","cpe1.m2.r640","cpe1.s1.r730","cpe1.s1.r730","d1f.optane.x86","d1p.optane.x86","g2.large.x86","m1.xlarge.x86","baremetal_2","m2.xlarge.x86","n2.xlarge.x86","s1.large.x86","baremetal_s","t1.small.x86","baremetal_0","x1.small.x86","baremetal_1e","x2.graphcore.x86","x2.xlarge.x86"],"preinstallable":false,"pricing":{},"licensed":false},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"project":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"ssh_keys":[{"href":"/ssh-keys/cf8abbdd-a484-43c3-ba62-627a16594594"},{"href":"/ssh-keys/502178f5-b985-466b-980e-f01ba028e5fc"},{"href":"/ssh-keys/2b38c95c-02dc-4ce8-961c-9d2ce8763647"},{"href":"/ssh-keys/343b1178-2dcb-40d9-a03b-6d5b58437e86"},{"href":"/ssh-keys/9af94154-e38f-4a77-8cd2-8e6455fc8129"},{"href":"/ssh-keys/22f9fd4c-ab3d-47f5-92ac-7d5703084d3d"},{"href":"/ssh-keys/56b9d292-8ed8-43c5-8687-a436979d1ac0"}],"project_lite":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"volumes":[],"ip_addresses":[{"id":"229ec20e-ec56-4a5b-8e61-c4eb15f60bdb","address_family":4,"netmask":"255.255.255.254","created_at":"2019-10-18T23:58:12Z","details":null,"tags":[],"public":true,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/a40d063e-2513-4c1e-a48e-1cafbab436e3"},"interface":{"href":"/ports/2a7610af-3631-499d-9cfa-cdd7e8547575"},"network":"147.75.100.108","address":"147.75.100.109","gateway":"147.75.100.108","href":"/ips/229ec20e-ec56-4a5b-8e61-c4eb15f60bdb"},{"id":"818ce056-d740-485e-b8ba-3558d53798ed","address_family":6,"netmask":"ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe","created_at":"2019-10-18T23:58:12Z","details":null,"tags":[],"public":true,"cidr":127,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/a40d063e-2513-4c1e-a48e-1cafbab436e3"},"interface":{"href":"/ports/2a7610af-3631-499d-9cfa-cdd7e8547575"},"network":"2604:1380:2000:ec00::","address":"2604:1380:2000:ec00::1","gateway":"2604:1380:2000:ec00::","href":"/ips/818ce056-d740-485e-b8ba-3558d53798ed"},{"id":"8701af8d-1d0a-47b9-8782-9439a7d2038c","address_family":4,"netmask":"255.255.255.254","created_at":"2019-10-18T23:58:12Z","details":null,"tags":[],"public":false,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/a40d063e-2513-4c1e-a48e-1cafbab436e3"},"interface":{"href":"/ports/2a7610af-3631-499d-9cfa-cdd7e8547575"},"network":"10.80.84.134","address":"10.80.84.135","gateway":"10.80.84.134","href":"/ips/8701af8d-1d0a-47b9-8782-9439a7d2038c"}],"created_by":{"id":"446476b8-a835-414a-8e9c-84925cc72705","full_name":"Markos Gogoulos","avatar_thumb_url":"https://www.gravatar.com/avatar/fafa2cd3f9d378981e87a993661859b4?d=mm","email":"mgogoulos@mist.io"},"plan":{"id":"e69c0169-4726-46ea-98f1-939c9e8a3607","slug":"t1.small.x86","name":"t1.small.x86","description":"Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.","line":"baremetal","specs":{"cpus":[{"count":1,"type":"Intel Atom C2550 @ 2.4Ghz"}],"memory":{"total":"8GB"},"drives":[{"count":1,"size":"80GB","type":"SSD"}],"nics":[{"count":2,"type":"1Gbps"}],"features":{"raid":false,"txt":true}},"legacy":false,"deployment_types":["on_demand","spot_market"],"available_in":[{"href":"/facilities/8e6470b3-b75e-47d1-bb93-45b225750975"},{"href":"/facilities/2b70eb8f-fa18-47c0-aba7-222a842362fd"},{"href":"/facilities/8ea03255-89f9-4e62-9d3f-8817db82ceed"},{"href":"/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09"}],"class":"t1.small.x86","pricing":{"hour":0.07}},"userdata":"#!/bin/bash\nexport DEBIAN_FRONTEND=noninteractive\napt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -\ncurl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -\ncat </etc/apt/sources.list.d/kubernetes.list\ndeb https://apt.kubernetes.io/ kubernetes-xenial main\nEOF\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\"\napt-get update\napt-get upgrade -y\napt-get install -y kubelet kubeadm kubectl\napt-mark hold kubelet kubeadm kubectl\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable\"\napt update\napt install -y docker-ce=18.06.2~ce~3-0~ubuntu\ncat > /etc/docker/daemon.json < /etc/fstab\nkubeadm join --discovery-token-unsafe-skip-ca-verification --token 07401b.f395accd246ae52d 147.75.102.15:6443\n","root_password":"t3%#d/J72D","switch_uuid":"a7994efc","network_ports":[{"id":"2a7610af-3631-499d-9cfa-cdd7e8547575","type":"NetworkBondPort","name":"bond0","data":{"bonded":true},"network_type":"layer3","native_virtual_network":null,"hardware":{"href":"/hardware/feea2550-963d-49cd-8ac2-3efa5cdc2883"},"virtual_networks":[],"connected_port":null,"href":"/ports/2a7610af-3631-499d-9cfa-cdd7e8547575"},{"id":"c33c170c-bdcd-49aa-862f-7e80b7a5b644","type":"NetworkPort","name":"eth0","data":{"mac":"0c:c4:7a:e5:43:c8","bonded":true},"bond":{"id":"2a7610af-3631-499d-9cfa-cdd7e8547575","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/feea2550-963d-49cd-8ac2-3efa5cdc2883"},"virtual_networks":[],"connected_port":{"href":"/ports/e93ce17a-e3ab-4208-a32c-d0a00b876869"},"href":"/ports/c33c170c-bdcd-49aa-862f-7e80b7a5b644"},{"id":"ea414f0a-f509-4b73-80f0-029f0163989d","type":"NetworkPort","name":"eth1","data":{"mac":"0c:c4:7a:e5:43:c9","bonded":true},"bond":{"id":"2a7610af-3631-499d-9cfa-cdd7e8547575","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/feea2550-963d-49cd-8ac2-3efa5cdc2883"},"virtual_networks":[],"connected_port":{"href":"/ports/aad81c51-bb88-41a4-a937-8db2e49e807d"},"href":"/ports/ea414f0a-f509-4b73-80f0-029f0163989d"}],"href":"/devices/a40d063e-2513-4c1e-a48e-1cafbab436e3"},{"id":"4d47a322-47e6-40cc-8402-e22b9933fb8f","short_id":"4d47a322","hostname":"k8s-worker-1","description":null,"state":"active","tags":["k8s-nodepool-pool1","k8s-cluster-cluster1"],"image_url":null,"billing_cycle":"hourly","user":"root","iqn":"iqn.2019-05.net.packet:device.4d47a322","locked":false,"bonding_mode":5,"created_at":"2019-05-24T11:59:52Z","updated_at":"2019-08-22T14:45:27Z","ipxe_script_url":null,"always_pxe":false,"storage":{},"customdata":{},"operating_system":{"id":"201bc259-982b-41a1-a4c1-bba01ce71f51","slug":"ubuntu_18_04","name":"Ubuntu 18.04 LTS","distro":"ubuntu","version":"18.04","provisionable_on":["baremetal_2a4","baremetal_2a5","c1.bloomberg.x86","c1.large.arm","baremetal_2a","c1.large.arm.xda","baremetal_2a2","c1.small.x86","baremetal_1","c1.xlarge.x86","baremetal_3","c2.large.anbox","c2.large.arm","c2.medium.x86","c2.small.x86","c3.medium.x86","c3.medium.x86","cpe1.c1.r720xd","cpe1.c1.r720xd","cpe1.g1.4028gr","cpe1.g1.4028gr","cpe1.m2.r640","cpe1.m2.r640","cpe1.s1.r730","cpe1.s1.r730","d1f.optane.x86","d1p.optane.x86","g2.large.x86","m1.xlarge.x86","baremetal_2","m2.xlarge.x86","n2.xlarge.x86","s1.large.x86","baremetal_s","t1.small.x86","baremetal_0","x1.small.x86","baremetal_1e","x2.graphcore.x86","x2.xlarge.x86"],"preinstallable":false,"pricing":{},"licensed":false},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"project":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"ssh_keys":[{"href":"/ssh-keys/cf8abbdd-a484-43c3-ba62-627a16594594"},{"href":"/ssh-keys/502178f5-b985-466b-980e-f01ba028e5fc"},{"href":"/ssh-keys/2b38c95c-02dc-4ce8-961c-9d2ce8763647"},{"href":"/ssh-keys/343b1178-2dcb-40d9-a03b-6d5b58437e86"},{"href":"/ssh-keys/9af94154-e38f-4a77-8cd2-8e6455fc8129"},{"href":"/ssh-keys/22f9fd4c-ab3d-47f5-92ac-7d5703084d3d"},{"href":"/ssh-keys/56b9d292-8ed8-43c5-8687-a436979d1ac0"}],"project_lite":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"volumes":[],"ip_addresses":[{"id":"d06ebdf8-57d1-4b07-974d-c23c013901b7","address_family":4,"netmask":"255.255.255.254","created_at":"2019-05-24T11:59:55Z","details":null,"tags":[],"public":true,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/4d47a322-47e6-40cc-8402-e22b9933fb8f"},"interface":{"href":"/ports/283fb58f-eacc-4f21-818e-619029b859aa"},"network":"147.75.85.136","address":"147.75.85.137","gateway":"147.75.85.136","href":"/ips/d06ebdf8-57d1-4b07-974d-c23c013901b7"},{"id":"31466841-6877-4197-966d-80125b8bf2a0","address_family":4,"netmask":"255.255.255.240","created_at":"2019-05-24T11:59:55Z","details":null,"tags":[],"public":false,"cidr":28,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/4d47a322-47e6-40cc-8402-e22b9933fb8f"},"interface":{"href":"/ports/283fb58f-eacc-4f21-818e-619029b859aa"},"network":"10.80.125.144","address":"10.80.125.146","gateway":"10.80.125.145","href":"/ips/31466841-6877-4197-966d-80125b8bf2a0"}],"created_by":{"id":"bd4f24f3-33f0-46a6-9528-4e31e2ba6074","full_name":"Dimitris Moraitis","avatar_thumb_url":"https://www.gravatar.com/avatar/702119decab6288093449009ab5af843?d=mm","email":"dimo@mist.io"},"plan":{"id":"e69c0169-4726-46ea-98f1-939c9e8a3607","slug":"baremetal_0","name":"t1.small.x86","description":"Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.","line":"baremetal","specs":{"cpus":[{"count":1,"type":"Intel Atom C2550 @ 2.4Ghz"}],"memory":{"total":"8GB"},"drives":[{"count":1,"size":"80GB","type":"SSD"}],"nics":[{"count":2,"type":"1Gbps"}],"features":{"raid":false,"txt":true}},"legacy":false,"deployment_types":["on_demand","spot_market"],"available_in":[{"href":"/facilities/8e6470b3-b75e-47d1-bb93-45b225750975"},{"href":"/facilities/2b70eb8f-fa18-47c0-aba7-222a842362fd"},{"href":"/facilities/8ea03255-89f9-4e62-9d3f-8817db82ceed"},{"href":"/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09"}],"class":"t1.small.x86","pricing":{"hour":0.07}},"userdata":"","switch_uuid":"a7994efc","network_ports":[{"id":"283fb58f-eacc-4f21-818e-619029b859aa","type":"NetworkBondPort","name":"bond0","data":{"bonded":true},"network_type":"layer3","native_virtual_network":null,"hardware":{"href":"/hardware/6c6046ef-df41-4c04-8522-69e4ec798024"},"virtual_networks":[],"connected_port":null,"href":"/ports/283fb58f-eacc-4f21-818e-619029b859aa"},{"id":"c0dcccb1-0c57-4be6-970a-3589cbb34355","type":"NetworkPort","name":"eth0","data":{"mac":"0c:c4:7a:e5:42:ce","bonded":true},"bond":{"id":"283fb58f-eacc-4f21-818e-619029b859aa","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/6c6046ef-df41-4c04-8522-69e4ec798024"},"virtual_networks":[],"connected_port":{"href":"/ports/57412b1f-f1fd-4071-8db2-5bc6494b9438"},"href":"/ports/c0dcccb1-0c57-4be6-970a-3589cbb34355"},{"id":"8fb7496b-32c1-45f4-8120-4b8faeaa57c3","type":"NetworkPort","name":"eth1","data":{"mac":"0c:c4:7a:e5:42:cf","bonded":true},"bond":{"id":"283fb58f-eacc-4f21-818e-619029b859aa","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/6c6046ef-df41-4c04-8522-69e4ec798024"},"virtual_networks":[],"connected_port":{"href":"/ports/d0803efe-50e7-492b-9044-b3ce9af609cc"},"href":"/ports/8fb7496b-32c1-45f4-8120-4b8faeaa57c3"}],"href":"/devices/4d47a322-47e6-40cc-8402-e22b9933fb8f"},{"id":"8a56bcad-e26f-4b0d-8d46-f490917ab2a3","short_id":"8a56bcad","hostname":"k8s-master-1","description":null,"state":"active","tags":["k8s-cluster-cluster1"],"image_url":null,"billing_cycle":"hourly","user":"root","iqn":"iqn.2019-05.net.packet:device.8a56bcad","locked":false,"bonding_mode":5,"created_at":"2019-05-24T11:59:51Z","updated_at":"2019-08-22T14:33:00Z","ipxe_script_url":null,"always_pxe":false,"storage":{},"customdata":{},"operating_system":{"id":"201bc259-982b-41a1-a4c1-bba01ce71f51","slug":"ubuntu_18_04","name":"Ubuntu 18.04 LTS","distro":"ubuntu","version":"18.04","provisionable_on":["baremetal_2a4","baremetal_2a5","c1.bloomberg.x86","c1.large.arm","baremetal_2a","c1.large.arm.xda","baremetal_2a2","c1.small.x86","baremetal_1","c1.xlarge.x86","baremetal_3","c2.large.anbox","c2.large.arm","c2.medium.x86","c2.small.x86","c3.medium.x86","c3.medium.x86","cpe1.c1.r720xd","cpe1.c1.r720xd","cpe1.g1.4028gr","cpe1.g1.4028gr","cpe1.m2.r640","cpe1.m2.r640","cpe1.s1.r730","cpe1.s1.r730","d1f.optane.x86","d1p.optane.x86","g2.large.x86","m1.xlarge.x86","baremetal_2","m2.xlarge.x86","n2.xlarge.x86","s1.large.x86","baremetal_s","t1.small.x86","baremetal_0","x1.small.x86","baremetal_1e","x2.graphcore.x86","x2.xlarge.x86"],"preinstallable":false,"pricing":{},"licensed":false},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"project":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"ssh_keys":[{"href":"/ssh-keys/cf8abbdd-a484-43c3-ba62-627a16594594"},{"href":"/ssh-keys/502178f5-b985-466b-980e-f01ba028e5fc"},{"href":"/ssh-keys/2b38c95c-02dc-4ce8-961c-9d2ce8763647"},{"href":"/ssh-keys/343b1178-2dcb-40d9-a03b-6d5b58437e86"},{"href":"/ssh-keys/9af94154-e38f-4a77-8cd2-8e6455fc8129"}],"project_lite":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df"},"volumes":[],"ip_addresses":[{"id":"f77aa56c-a781-441d-bb40-c639db16a3cc","address_family":4,"netmask":"255.255.255.254","created_at":"2019-05-24T11:59:54Z","details":null,"tags":[],"public":true,"cidr":31,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/8a56bcad-e26f-4b0d-8d46-f490917ab2a3"},"interface":{"href":"/ports/51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1"},"network":"147.75.102.14","address":"147.75.102.15","gateway":"147.75.102.14","href":"/ips/f77aa56c-a781-441d-bb40-c639db16a3cc"},{"id":"24502d6d-a633-4650-9650-6c9d3de50b72","address_family":4,"netmask":"255.255.255.240","created_at":"2019-05-24T11:59:54Z","details":null,"tags":[],"public":false,"cidr":28,"management":true,"manageable":true,"enabled":true,"global_ip":null,"customdata":{},"project":{},"project_lite":{},"facility":{"id":"8e6470b3-b75e-47d1-bb93-45b225750975","name":"Amsterdam, NL","code":"ams1","features":["baremetal","storage","global_ipv4","backend_transfer","layer_2"],"address":{"href":"#0688e909-647e-4b21-bdf2-fc056d993fc5"},"ip_ranges":["2604:1380:2000::/36","147.75.204.0/23","147.75.100.0/22","147.75.80.0/22","147.75.32.0/23"]},"assigned_to":{"href":"/devices/8a56bcad-e26f-4b0d-8d46-f490917ab2a3"},"interface":{"href":"/ports/51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1"},"network":"10.80.125.128","address":"10.80.125.130","gateway":"10.80.125.129","href":"/ips/24502d6d-a633-4650-9650-6c9d3de50b72"}],"created_by":{"id":"bd4f24f3-33f0-46a6-9528-4e31e2ba6074","full_name":"Dimitris Moraitis","avatar_thumb_url":"https://www.gravatar.com/avatar/702119decab6288093449009ab5af843?d=mm","email":"dimo@mist.io"},"plan":{"id":"e69c0169-4726-46ea-98f1-939c9e8a3607","slug":"baremetal_0","name":"t1.small.x86","description":"Our Type 0 configuration is a general use \"cloud killer\" server, with a Intel Atom 2.4Ghz processor and 8GB of RAM.","line":"baremetal","specs":{"cpus":[{"count":1,"type":"Intel Atom C2550 @ 2.4Ghz"}],"memory":{"total":"8GB"},"drives":[{"count":1,"size":"80GB","type":"SSD"}],"nics":[{"count":2,"type":"1Gbps"}],"features":{"raid":false,"txt":true}},"legacy":false,"deployment_types":["on_demand","spot_market"],"available_in":[{"href":"/facilities/8e6470b3-b75e-47d1-bb93-45b225750975"},{"href":"/facilities/2b70eb8f-fa18-47c0-aba7-222a842362fd"},{"href":"/facilities/8ea03255-89f9-4e62-9d3f-8817db82ceed"},{"href":"/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09"}],"class":"t1.small.x86","pricing":{"hour":0.07}},"userdata":"","switch_uuid":"ddb086ff","network_ports":[{"id":"51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1","type":"NetworkBondPort","name":"bond0","data":{"bonded":true},"network_type":"layer3","native_virtual_network":null,"hardware":{"href":"/hardware/7f262628-7db2-4b4b-90b1-41529818c7c0"},"virtual_networks":[],"connected_port":null,"href":"/ports/51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1"},{"id":"2281afe5-c934-407a-abe0-b1f315291d3d","type":"NetworkPort","name":"eth0","data":{"mac":"0c:c4:7a:e5:43:04","bonded":true},"bond":{"id":"51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/7f262628-7db2-4b4b-90b1-41529818c7c0"},"virtual_networks":[],"connected_port":{"href":"/ports/cba6a9dd-550d-4e11-a93c-3a7b83bfaa65"},"href":"/ports/2281afe5-c934-407a-abe0-b1f315291d3d"},{"id":"1f351695-103b-4d92-9c7e-a6ce03904b12","type":"NetworkPort","name":"eth1","data":{"mac":"0c:c4:7a:e5:43:05","bonded":true},"bond":{"id":"51a3ad77-4eb5-4f81-ab6f-8de3e1db15e1","name":"bond0"},"native_virtual_network":null,"hardware":{"href":"/hardware/7f262628-7db2-4b4b-90b1-41529818c7c0"},"virtual_networks":[],"connected_port":{"href":"/ports/c7466539-f5c6-41b9-9bb2-97490d6b7c10"},"href":"/ports/1f351695-103b-4d92-9c7e-a6ce03904b12"}],"href":"/devices/8a56bcad-e26f-4b0d-8d46-f490917ab2a3"}],"meta":{"first":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df/devices?page=1"},"previous":null,"self":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df/devices?page=1"},"next":null,"last":{"href":"/projects/3d27fd13-0466-4878-be22-9a4b5595a3df/devices?page=1"},"current_page":1,"last_page":1,"total":4}} +` + +const cloudinitDefault = "IyEvYmluL2Jhc2gKZXhwb3J0IERFQklBTl9GUk9OVEVORD1ub25pbnRlcmFjdGl2ZQphcHQtZ2V0IHVwZGF0ZSAmJiBhcHQtZ2V0IGluc3RhbGwgLXkgYXB0LXRyYW5zcG9ydC1odHRwcyBjYS1jZXJ0aWZpY2F0ZXMgY3VybCBzb2Z0d2FyZS1wcm9wZXJ0aWVzLWNvbW1vbgpjdXJsIC1mc1NMIGh0dHBzOi8vZG93bmxvYWQuZG9ja2VyLmNvbS9saW51eC91YnVudHUvZ3BnIHwgYXB0LWtleSBhZGQgLQpjdXJsIC1zIGh0dHBzOi8vcGFja2FnZXMuY2xvdWQuZ29vZ2xlLmNvbS9hcHQvZG9jL2FwdC1rZXkuZ3BnIHwgYXB0LWtleSBhZGQgLQpjYXQgPDxFT0YgPi9ldGMvYXB0L3NvdXJjZXMubGlzdC5kL2t1YmVybmV0ZXMubGlzdApkZWIgaHR0cHM6Ly9hcHQua3ViZXJuZXRlcy5pby8ga3ViZXJuZXRlcy14ZW5pYWwgbWFpbgpFT0YKYWRkLWFwdC1yZXBvc2l0b3J5ICAgImRlYiBbYXJjaD1hbWQ2NF0gaHR0cHM6Ly9kb3dubG9hZC5kb2NrZXIuY29tL2xpbnV4L3VidW50dSAgICQobHNiX3JlbGVhc2UgLWNzKSAgIHN0YWJsZSIKYXB0LWdldCB1cGRhdGUKYXB0LWdldCB1cGdyYWRlIC15CmFwdC1nZXQgaW5zdGFsbCAteSBrdWJlbGV0IGt1YmVhZG0ga3ViZWN0bAphcHQtbWFyayBob2xkIGt1YmVsZXQga3ViZWFkbSBrdWJlY3RsCmN1cmwgLWZzU0wgaHR0cHM6Ly9kb3dubG9hZC5kb2NrZXIuY29tL2xpbnV4L3VidW50dS9ncGcgfCBhcHQta2V5IGFkZCAtCmFkZC1hcHQtcmVwb3NpdG9yeSAiZGViIFthcmNoPWFtZDY0XSBodHRwczovL2Rvd25sb2FkLmRvY2tlci5jb20vbGludXgvdWJ1bnR1IGJpb25pYyBzdGFibGUiCmFwdCB1cGRhdGUKYXB0IGluc3RhbGwgLXkgZG9ja2VyLWNlPTE4LjA2LjJ+Y2V+My0wfnVidW50dQpjYXQgPiAvZXRjL2RvY2tlci9kYWVtb24uanNvbiA8PEVPRgp7CiAgImV4ZWMtb3B0cyI6IFsibmF0aXZlLmNncm91cGRyaXZlcj1zeXN0ZW1kIl0sCiAgImxvZy1kcml2ZXIiOiAianNvbi1maWxlIiwKICAibG9nLW9wdHMiOiB7CiAgICAibWF4LXNpemUiOiAiMTAwbSIKICB9LAogICJzdG9yYWdlLWRyaXZlciI6ICJvdmVybGF5MiIKfQpFT0YKbWtkaXIgLXAgL2V0Yy9zeXN0ZW1kL3N5c3RlbS9kb2NrZXIuc2VydmljZS5kCnN5c3RlbWN0bCBkYWVtb24tcmVsb2FkCnN5c3RlbWN0bCByZXN0YXJ0IGRvY2tlcgpzd2Fwb2ZmIC1hCm12IC9ldGMvZnN0YWIgL2V0Yy9mc3RhYi5vbGQgJiYgZ3JlcCAtdiBzd2FwIC9ldGMvZnN0YWIub2xkID4gL2V0Yy9mc3RhYgprdWJlYWRtIGpvaW4gLS1kaXNjb3ZlcnktdG9rZW4tdW5zYWZlLXNraXAtY2EtdmVyaWZpY2F0aW9uIC0tdG9rZW4ge3suQm9vdHN0cmFwVG9rZW5JRH19Lnt7LkJvb3RzdHJhcFRva2VuU2VjcmV0fX0ge3suQVBJU2VydmVyRW5kcG9pbnR9fQo=" + +func newTestPacketManagerRest(t *testing.T, url string) *packetManagerRest { + manager := &packetManagerRest{ + baseURL: url, + clusterName: "cluster1", + projectID: "3d27fd13-0466-4878-be22-9a4b5595a3df", + apiServerEndpoint: "147.75.102.15:6443", + facility: "ams1", + os: "ubuntu_18_04", + plan: "t1.small.x86", + billing: "hourly", + cloudinit: cloudinitDefault, + reservation: "prefer", + hostnamePattern: "k8s-{{.ClusterName}}-{{.NodeGroup}}-{{.RandString8}}", + } + return manager +} +func TestListPacketDevices(t *testing.T) { + var m *packetManagerRest + server := NewHttpServerMock() + defer server.Close() + if len(os.Getenv("PACKET_AUTH_TOKEN")) > 0 { + // If auth token set in env, hit the actual Packet API + m = newTestPacketManagerRest(t, "https://api.packet.net") + } else { + // Set up a mock Packet API + m = newTestPacketManagerRest(t, server.URL) + server.On("handle", "/projects/"+m.projectID+"/devices").Return(listPacketDevicesResponse).Times(2) + } + + _, err := m.listPacketDevices() + assert.NoError(t, err) + + c, err := m.nodeGroupSize("pool1") + assert.NoError(t, err) + assert.Equal(t, int(1), c) // One device in nodepool + + mock.AssertExpectationsForObjects(t, server) +} diff --git a/cluster-autoscaler/cloudprovider/packet/packet_node_group.go b/cluster-autoscaler/cloudprovider/packet/packet_node_group.go index 8f528d50e94..ac33a17562f 100644 --- a/cluster-autoscaler/cloudprovider/packet/packet_node_group.go +++ b/cluster-autoscaler/cloudprovider/packet/packet_node_group.go @@ -132,7 +132,7 @@ func (ng *packetNodeGroup) DeleteNodes(nodes []*apiv1.Node) error { if cachedSize-len(ng.nodesToDelete)-len(nodes) < ng.MinSize() { ng.nodesToDeleteMutex.Unlock() klog.V(1).Infof("UnLocking nodesToDeleteMutex") - return fmt.Errorf("deleting nodes would take nodegroup below minimum size") + return fmt.Errorf("deleting nodes would take nodegroup below minimum size %d", ng.minSize) } // otherwise, add the nodes to the batch and release the lock ng.nodesToDelete = append(ng.nodesToDelete, nodes...) @@ -180,14 +180,6 @@ func (ng *packetNodeGroup) DeleteNodes(nodes []*apiv1.Node) error { } klog.V(0).Infof("Deleting nodes: %v", nodeNames) - /*updatePossible, currentStatus, err := ng.magnumManager.canUpdate() - if err != nil { - return fmt.Errorf("could not check if cluster is ready to delete nodes: %v", err) - } - if !updatePossible { - return fmt.Errorf("can not delete nodes, cluster is in %s status", currentStatus) - }*/ - // Double check that the total number of batched nodes for deletion will not take the node group below its minimum size if cachedSize-len(nodes) < ng.MinSize() { return fmt.Errorf("size decrease too large, desired:%d min:%d", cachedSize-len(nodes), ng.MinSize()) diff --git a/cluster-autoscaler/cloudprovider/packet/packet_node_group_test.go b/cluster-autoscaler/cloudprovider/packet/packet_node_group_test.go new file mode 100644 index 00000000000..c05f5de14d0 --- /dev/null +++ b/cluster-autoscaler/cloudprovider/packet/packet_node_group_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2019 The Kubernetes 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 packet + +import ( + "os" + "sync" + "testing" + "time" + + apiv1 "k8s.io/api/core/v1" + . "k8s.io/autoscaler/cluster-autoscaler/utils/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestIncreaseDecreaseSize(t *testing.T) { + var m *packetManagerRest + server := NewHttpServerMock() + defer server.Close() + assert.Equal(t, true, true) + if len(os.Getenv("PACKET_AUTH_TOKEN")) > 0 { + // If auth token set in env, hit the actual Packet API + m = newTestPacketManagerRest(t, "https://api.packet.net") + } else { + // Set up a mock Packet API + m = newTestPacketManagerRest(t, server.URL) + server.On("handle", "/projects/"+m.projectID+"/devices").Return(listPacketDevicesResponse).Times(4) + server.On("handle", "/projects/"+m.projectID+"/devices").Return(listPacketDevicesResponseAfterCreate).Times(2) + server.On("handle", "/projects/"+m.projectID+"/devices").Return(listPacketDevicesResponse) + } + clusterUpdateLock := sync.Mutex{} + ng := &packetNodeGroup{ + packetManager: m, + id: "pool1", + clusterUpdateMutex: &clusterUpdateLock, + minSize: 1, + maxSize: 10, + targetSize: new(int), + waitTimeStep: 30 * time.Second, + deleteBatchingDelay: 2 * time.Second, + } + + n1, err := ng.Nodes() + assert.NoError(t, err) + assert.Equal(t, int(1), len(n1)) + + // Try to increase pool with negative size, this should return an error + err = ng.IncreaseSize(-1) + assert.Error(t, err) + + // Now try to increase the pool size by 2, that should work + err = ng.IncreaseSize(2) + assert.NoError(t, err) + + if len(os.Getenv("PACKET_AUTH_TOKEN")) > 0 { + // If testing with actual API give it some time until the nodes bootstrap + time.Sleep(420 * time.Second) + } + n2, err := ng.packetManager.getNodeNames(ng.id) + assert.NoError(t, err) + // Assert that the nodepool size is now 3 + assert.Equal(t, int(3), len(n2)) + + // Let's try to delete the new nodes + nodes := []*apiv1.Node{} + for _, node := range n2 { + if node != "k8s-worker-1" { + nodes = append(nodes, BuildTestNode(node, 1000, 1000)) + } + } + err = ng.DeleteNodes(nodes) + assert.NoError(t, err) + + // Wait a few seconds if talking to the actual Packet API + if len(os.Getenv("PACKET_AUTH_TOKEN")) > 0 { + time.Sleep(10 * time.Second) + } + + // Make sure that there were no errors and the nodepool size is once again 1 + n3, err := ng.Nodes() + assert.NoError(t, err) + assert.Equal(t, int(1), len(n3)) + mock.AssertExpectationsForObjects(t, server) +}