Skip to content

Commit

Permalink
Fix: Resetting always_pxe flag as per user configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
codinja1188 committed Aug 24, 2023
1 parent 43a33f7 commit f27af9a
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 54 deletions.
4 changes: 2 additions & 2 deletions docs/metal_device_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Creates a device.
Creates a device in the specified project. A plan, hostname, operating system, and either metro or facility is required.

```
metal device create -p <project_id> (-m <metro> | -f <facility>) -P <plan> -H <hostname> -O <operating_system> [-u <userdata> | --userdata-file <filepath>] [-c <customdata>] [-t <tags>] [-r <hardware_reservation_id>] [-I <ipxe_script_url>] [--always-pxe] [--spot-instance] [--spot-price-max=<max_price>] [flags]
metal device create -p <project_id> (-m <metro> | -f <facility>) -P <plan> -H <hostname> -O <operating_system> [-u <userdata> | --userdata-file <filepath>] [-c <customdata>] [-t <tags>] [-r <hardware_reservation_id>] [-I <ipxe_script_url>] [--alwaysPxe] [--spot-instance] [--spot-price-max=<max_price>] [flags]
```

### Examples
Expand All @@ -23,7 +23,7 @@ metal device create -p <project_id> (-m <metro> | -f <facility>) -P <plan> -H <h
### Options

```
-a, --always-pxe Sets whether the device always PXE boots on reboot.
-a, --alwaysPxe string Sets whether the device always PXE boots on reboot.
-b, --billing-cycle string Billing cycle (default "hourly")
-c, --customdata string Custom data to be included with your device's metadata.
-f, --facility string Code of the facility where the device will be created
Expand Down
4 changes: 2 additions & 2 deletions docs/metal_device_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Updates a device.
Updates the hostname of a device. Updates or adds a description, tags, userdata, custom data, and iPXE settings for an already provisioned device. Can also lock or unlock future changes to the device.

```
metal device update -i <device_id> [-H <hostname>] [-d <description>] [--locked <boolean>] [-t <tags>] [-u <userdata>] [-c <customdata>] [-s <ipxe_script_url>] [--always-pxe] [flags]
metal device update -i <device_id> [-H <hostname>] [-d <description>] [--locked <boolean>] [-t <tags>] [-u <userdata>] [-c <customdata>] [-s <ipxe_script_url>] [--alwaysPxe] [flags]
```

### Examples
Expand All @@ -20,7 +20,7 @@ metal device update -i <device_id> [-H <hostname>] [-d <description>] [--locked
### Options

```
-a, --always-pxe Sets the device to always iPXE on reboot.
-a, --alwaysPxe string Sets the device to always iPXE on reboot.
-c, --customdata string Adds or updates custom data to be included with your device's metadata.
-d, --description string Adds or updates the description for the device.
-h, --help help for update
Expand Down
99 changes: 86 additions & 13 deletions internal/devices/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ package devices

import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"time"

metal "github.com/equinix-labs/metal-go/metal/v1"
"github.com/spf13/cobra"
Expand All @@ -46,15 +49,15 @@ func (c *Client) Create() *cobra.Command {
tags []string
ipxescripturl string
publicIPv4SubnetSize int
alwaysPXE bool
alwaysPxe string
hardwareReservationID string
spotInstance bool
spotPriceMax float64
terminationTime string
)

createDeviceCmd := &cobra.Command{
Use: `create -p <project_id> (-m <metro> | -f <facility>) -P <plan> -H <hostname> -O <operating_system> [-u <userdata> | --userdata-file <filepath>] [-c <customdata>] [-t <tags>] [-r <hardware_reservation_id>] [-I <ipxe_script_url>] [--always-pxe] [--spot-instance] [--spot-price-max=<max_price>]`,
Use: `create -p <project_id> (-m <metro> | -f <facility>) -P <plan> -H <hostname> -O <operating_system> [-u <userdata> | --userdata-file <filepath>] [-c <customdata>] [-t <tags>] [-r <hardware_reservation_id>] [-I <ipxe_script_url>] [--alwaysPxe] [--spot-instance] [--spot-price-max=<max_price>]`,
Short: "Creates a device.",
Long: "Creates a device in the specified project. A plan, hostname, operating system, and either metro or facility is required.",
Example: ` # Provisions a c3.small.x86 in the Dallas metro running Ubuntu 20.04:
Expand All @@ -75,18 +78,25 @@ func (c *Client) Create() *cobra.Command {
}
userdata = string(userdataRaw)
}
// var endDt time.Time

// if terminationTime != "" {
// parsedTime, err := time.Parse(time.RFC3339, terminationTime)
// if err != nil {
// return fmt.Errorf("could not parse time %q: %w", terminationTime, err)
// }
// endDt = parsedTime
// }
var endDt time.Time

if terminationTime != "" {
parsedTime, err := time.Parse(time.RFC3339, terminationTime)
if err != nil {
return fmt.Errorf("could not parse time %q: %w", terminationTime, err)
}
endDt = parsedTime
}

formatedCdata := make(map[string]interface{})
if customdata != "" {
err := json.Unmarshal([]byte(customdata), &formatedCdata)
if err != nil {
return fmt.Errorf("could not convert customedata :%w", err)
}
}
var facilityArgs []string

// var deviceCreateInFacilityInput *metal.DeviceCreateInFacilityInput
var request metal.ApiCreateDeviceRequest
if facility != "" {
facilityArgs = append(facilityArgs, facility)
Expand All @@ -97,10 +107,43 @@ func (c *Client) Create() *cobra.Command {
Plan: plan,
OperatingSystem: operatingSystem,
Hostname: &hostname,
Userdata: &userdata,
Tags: tags,
},
}

if billingCycle != "" {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetBillingCycle(billingCycle)
}
if alwaysPxe != "" {
if strings.Compare(alwaysPxe, "true") == 0 {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetAlwaysPxe(true)
}
if strings.Compare(alwaysPxe, "false") == 0 {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetAlwaysPxe(false)
}
}

if ipxescripturl != "" {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetIpxeScriptUrl(ipxescripturl)
}
if publicIPv4SubnetSize != 0 {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetPublicIpv4SubnetSize(int32(publicIPv4SubnetSize))
}
if terminationTime != "" {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetTerminationTime(endDt)
}
facilityDeviceRequest.DeviceCreateInFacilityInput.SetSpotInstance(spotInstance)
facilityDeviceRequest.DeviceCreateInFacilityInput.SetSpotPriceMax(float32(spotPriceMax))
facilityDeviceRequest.DeviceCreateInFacilityInput.SetCustomdata(formatedCdata)

if hardwareReservationID != "" {
facilityDeviceRequest.DeviceCreateInFacilityInput.SetHardwareReservationId(hardwareReservationID)
}

request = c.Service.CreateDevice(context.Background(), projectID).CreateDeviceRequest(facilityDeviceRequest).Include(nil).Exclude(nil)
}

if metro != "" {

metroDeviceRequest := metal.CreateDeviceRequest{
Expand All @@ -109,9 +152,39 @@ func (c *Client) Create() *cobra.Command {
Plan: plan,
OperatingSystem: operatingSystem,
Hostname: &hostname,
Userdata: &userdata,
Tags: tags,
},
}
if billingCycle != "" {
metroDeviceRequest.DeviceCreateInMetroInput.SetBillingCycle(billingCycle)
}

if alwaysPxe != "" {
if strings.Compare(alwaysPxe, "true") == 0 {
metroDeviceRequest.DeviceCreateInMetroInput.SetAlwaysPxe(true)
}
if strings.Compare(alwaysPxe, "false") == 0 {
metroDeviceRequest.DeviceCreateInMetroInput.SetAlwaysPxe(false)
}
}

if ipxescripturl != "" {
metroDeviceRequest.DeviceCreateInMetroInput.SetIpxeScriptUrl(ipxescripturl)
}
if publicIPv4SubnetSize != 0 {
metroDeviceRequest.DeviceCreateInMetroInput.SetPublicIpv4SubnetSize(int32(publicIPv4SubnetSize))
}
if terminationTime != "" {
metroDeviceRequest.DeviceCreateInMetroInput.SetTerminationTime(endDt)
}
metroDeviceRequest.DeviceCreateInMetroInput.SetSpotInstance(spotInstance)
metroDeviceRequest.DeviceCreateInMetroInput.SetSpotPriceMax(float32(spotPriceMax))
metroDeviceRequest.DeviceCreateInMetroInput.SetCustomdata(formatedCdata)

if hardwareReservationID != "" {
metroDeviceRequest.DeviceCreateInMetroInput.SetHardwareReservationId(hardwareReservationID)
}
request = c.Service.CreateDevice(context.Background(), projectID).CreateDeviceRequest(metroDeviceRequest).Include(nil).Exclude(nil)
}
device, _, err := request.Execute()
Expand Down Expand Up @@ -146,7 +219,7 @@ func (c *Client) Create() *cobra.Command {
createDeviceCmd.Flags().IntVarP(&publicIPv4SubnetSize, "public-ipv4-subnet-size", "S", 0, "Size of the public IPv4 subnet.")
createDeviceCmd.Flags().StringVarP(&hardwareReservationID, "hardware-reservation-id", "r", "", "The UUID of a hardware reservation, if you are provisioning a server from your reserved hardware.")
createDeviceCmd.Flags().StringVarP(&billingCycle, "billing-cycle", "b", "hourly", "Billing cycle")
createDeviceCmd.Flags().BoolVarP(&alwaysPXE, "always-pxe", "a", false, "Sets whether the device always PXE boots on reboot.")
createDeviceCmd.Flags().StringVarP(&alwaysPxe, "alwaysPxe", "a", "", "Sets whether the device always PXE boots on reboot.")
createDeviceCmd.Flags().BoolVarP(&spotInstance, "spot-instance", "s", false, "Provisions the device as a spot instance.")
createDeviceCmd.Flags().Float64VarP(&spotPriceMax, "spot-price-max", "", 0, `Sets the maximum spot market price for the device: --spot-price-max=1.2`)
createDeviceCmd.Flags().StringVarP(&terminationTime, "termination-time", "T", "", `Device termination time: --termination-time="15:04:05"`)
Expand Down
19 changes: 12 additions & 7 deletions internal/devices/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"context"
"encoding/json"
"fmt"
"strings"

metal "github.com/equinix-labs/metal-go/metal/v1"

Expand All @@ -37,15 +38,14 @@ func (c *Client) Update() *cobra.Command {
userdata string
hostname string
tags []string
alwaysPXE bool
alwaysPxe string
ipxescripturl string
customdata string
deviceID string
)

// updateDeviceCmd represents the updateDevice command
updateDeviceCmd := &cobra.Command{
Use: `update -i <device_id> [-H <hostname>] [-d <description>] [--locked <boolean>] [-t <tags>] [-u <userdata>] [-c <customdata>] [-s <ipxe_script_url>] [--always-pxe]`,
Use: `update -i <device_id> [-H <hostname>] [-d <description>] [--locked <boolean>] [-t <tags>] [-u <userdata>] [-c <customdata>] [-s <ipxe_script_url>] [--alwaysPxe]`,
Short: "Updates a device.",
Long: "Updates the hostname of a device. Updates or adds a description, tags, userdata, custom data, and iPXE settings for an already provisioned device. Can also lock or unlock future changes to the device.",
Example: ` # Updates the hostname of a device:
Expand Down Expand Up @@ -75,8 +75,13 @@ func (c *Client) Update() *cobra.Command {
deviceUpdate.Tags = tags
}

if alwaysPXE {
deviceUpdate.AlwaysPxe = &alwaysPXE
if alwaysPxe != "" {
if strings.Compare(alwaysPxe, "true") == 0 {
deviceUpdate.SetAlwaysPxe(true)
}
if strings.Compare(alwaysPxe, "false") == 0 {
deviceUpdate.SetAlwaysPxe(false)
}
}

if ipxescripturl != "" {
Expand Down Expand Up @@ -111,10 +116,10 @@ func (c *Client) Update() *cobra.Command {
updateDeviceCmd.Flags().StringVarP(&userdata, "userdata", "u", "", "Adds or updates the userdata for the device.")
updateDeviceCmd.Flags().BoolVarP(&locked, "locked", "l", false, "Locks or unlocks the device for future changes.")
updateDeviceCmd.Flags().StringSliceVarP(&tags, "tags", "t", []string{}, `Adds or updates the tags for the device --tags="tag1,tag2".`)
updateDeviceCmd.Flags().BoolVarP(&alwaysPXE, "always-pxe", "a", false, "Sets the device to always iPXE on reboot.")
updateDeviceCmd.Flags().StringVarP(&alwaysPxe, "alwaysPxe", "a", "", "Sets the device to always iPXE on reboot.")
updateDeviceCmd.Flags().StringVarP(&ipxescripturl, "ipxe-script-url", "s", "", "Add or update the URL of the iPXE script.")
updateDeviceCmd.Flags().StringVarP(&customdata, "customdata", "c", "", "Adds or updates custom data to be included with your device's metadata.")

_ = updateDeviceCmd.MarkFlagRequired("id")

return updateDeviceCmd
}
24 changes: 19 additions & 5 deletions test/e2e/devices/devicecreatetest/device_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (

func TestCli_Devices_create(t *testing.T) {
var projectId, deviceId string
var err error
var resp bool
subCommand := "device"
consumerToken := ""
apiURL := ""
Expand All @@ -40,10 +42,13 @@ func TestCli_Devices_create(t *testing.T) {
want: &cobra.Command{},
cmdFunc: func(t *testing.T, c *cobra.Command) {
root := c.Root()
projectId = helper.Create_test_project("create-device-pro")
projectId, err = helper.CreateTestProject("create-device-pro")
if err != nil {
t.Error(err)
}
if len(projectId) != 0 {

root.SetArgs([]string{subCommand, "create", "-p", projectId, "-P", "c3.small.x86", "-m", "da", "-O", "ubuntu_20_04", "-H", "create-device-dev"})
root.SetArgs([]string{subCommand, "create", "-p", projectId, "-P", "m3.small.x86", "-m", "da", "-O", "ubuntu_20_04", "-H", "create-device-dev"})
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
Expand All @@ -67,9 +72,18 @@ func TestCli_Devices_create(t *testing.T) {
// Extract the ID from the match
if len(match) > 1 {
deviceId = strings.TrimSpace(match[1])
if helper.Is_Device_state_active(deviceId) {
helper.Clean_test_device(deviceId)
helper.Clean_test_project(projectId)
resp, err = helper.IsDeviceStateActive(deviceId)
if err == nil && resp == true {
err = helper.CleanTestDevice(deviceId)
if err != nil {
t.Error(err)
}
err = helper.CleanTestProject(projectId)
if err != nil {
t.Error(err)
}
} else {
t.Error(err)
}
}
}
Expand Down
27 changes: 22 additions & 5 deletions test/e2e/devices/devicegettest/device_get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (

func TestCli_Devices_get(t *testing.T) {
var projectId, deviceId string
var err error
var resp bool
subCommand := "device"
consumerToken := ""
apiURL := ""
Expand All @@ -39,8 +41,14 @@ func TestCli_Devices_get(t *testing.T) {
want: &cobra.Command{},
cmdFunc: func(t *testing.T, c *cobra.Command) {
root := c.Root()
projectId = helper.Create_test_project("get-by-device-id-pro")
deviceId = helper.Create_test_device(projectId, "get-by-device-id-dev")
projectId, err = helper.CreateTestProject("get-by-device-id-pro")
if err != nil {
t.Error(err)
}
deviceId, err = helper.CreateTestDevice(projectId, "get-by-device-id-dev")
if err != nil {
t.Error(err)
}
root.SetArgs([]string{subCommand, "get", "-i", deviceId})
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
Expand All @@ -55,9 +63,18 @@ func TestCli_Devices_get(t *testing.T) {
t.Error("expected output should include " + deviceId)
}
if len(projectId) != 0 && len(deviceId) != 0 {
if helper.Is_Device_state_active(deviceId) {
helper.Clean_test_device(deviceId)
helper.Clean_test_project(projectId)
resp, err = helper.IsDeviceStateActive(deviceId)
if err == nil && resp == true {
err = helper.CleanTestDevice(deviceId)
if err != nil {
t.Error(err)
}
err = helper.CleanTestProject(projectId)
if err != nil {
t.Error(err)
}
} else {
t.Error(err)
}
}
},
Expand Down
Loading

0 comments on commit f27af9a

Please sign in to comment.