instance.go raw

   1  package govultr
   2  
   3  import (
   4  	"context"
   5  	"fmt"
   6  	"net/http"
   7  
   8  	"github.com/google/go-querystring/query"
   9  )
  10  
  11  const instancePath = "/v2/instances"
  12  
  13  // InstanceService is the interface to interact with the instance endpoints on the Vultr API
  14  // Link: https://www.vultr.com/api/#tag/instances
  15  type InstanceService interface {
  16  	Create(ctx context.Context, instanceReq *InstanceCreateReq) (*Instance, *http.Response, error)
  17  	Get(ctx context.Context, instanceID string) (*Instance, *http.Response, error)
  18  	Update(ctx context.Context, instanceID string, instanceReq *InstanceUpdateReq) (*Instance, *http.Response, error)
  19  	Delete(ctx context.Context, instanceID string) error
  20  	List(ctx context.Context, options *ListOptions) ([]Instance, *Meta, *http.Response, error)
  21  
  22  	Start(ctx context.Context, instanceID string) error
  23  	Halt(ctx context.Context, instanceID string) error
  24  	Reboot(ctx context.Context, instanceID string) error
  25  	Reinstall(ctx context.Context, instanceID string, reinstallReq *ReinstallReq) (*Instance, *http.Response, error)
  26  
  27  	MassStart(ctx context.Context, instanceList []string) error
  28  	MassHalt(ctx context.Context, instanceList []string) error
  29  	MassReboot(ctx context.Context, instanceList []string) error
  30  
  31  	Restore(ctx context.Context, instanceID string, restoreReq *RestoreReq) (*http.Response, error)
  32  
  33  	GetBandwidth(ctx context.Context, instanceID string) (*Bandwidth, *http.Response, error)
  34  	GetNeighbors(ctx context.Context, instanceID string) (*Neighbors, *http.Response, error)
  35  
  36  	ListVPCInfo(ctx context.Context, instanceID string, options *ListOptions) ([]VPCInfo, *Meta, *http.Response, error)
  37  	AttachVPC(ctx context.Context, instanceID, vpcID string) error
  38  	DetachVPC(ctx context.Context, instanceID, vpcID string) error
  39  
  40  	ISOStatus(ctx context.Context, instanceID string) (*Iso, *http.Response, error)
  41  	AttachISO(ctx context.Context, instanceID, isoID string) (*http.Response, error)
  42  	DetachISO(ctx context.Context, instanceID string) (*http.Response, error)
  43  
  44  	GetBackupSchedule(ctx context.Context, instanceID string) (*BackupSchedule, *http.Response, error)
  45  	SetBackupSchedule(ctx context.Context, instanceID string, backup *BackupScheduleReq) (*http.Response, error)
  46  
  47  	CreateIPv4(ctx context.Context, instanceID string, reboot *bool) (*IPv4, *http.Response, error)
  48  	ListIPv4(ctx context.Context, instanceID string, option *ListOptions) ([]IPv4, *Meta, *http.Response, error)
  49  	DeleteIPv4(ctx context.Context, instanceID, ip string) error
  50  	ListIPv6(ctx context.Context, instanceID string, option *ListOptions) ([]IPv6, *Meta, *http.Response, error)
  51  
  52  	CreateReverseIPv6(ctx context.Context, instanceID string, reverseReq *ReverseIP) error
  53  	ListReverseIPv6(ctx context.Context, instanceID string) ([]ReverseIP, *http.Response, error)
  54  	DeleteReverseIPv6(ctx context.Context, instanceID, ip string) error
  55  
  56  	CreateReverseIPv4(ctx context.Context, instanceID string, reverseReq *ReverseIP) error
  57  	DefaultReverseIPv4(ctx context.Context, instanceID, ip string) error
  58  
  59  	GetUserData(ctx context.Context, instanceID string) (*UserData, *http.Response, error)
  60  
  61  	GetUpgrades(ctx context.Context, instanceID string) (*Upgrades, *http.Response, error)
  62  
  63  	// Deprecated: VPC2 is no longer supported
  64  	ListVPC2Info(ctx context.Context, instanceID string, options *ListOptions) ([]VPC2Info, *Meta, *http.Response, error)
  65  
  66  	// Deprecated: VPC2 is no longer supported
  67  	AttachVPC2(ctx context.Context, instanceID string, vpc2Req *AttachVPC2Req) error
  68  
  69  	// Deprecated: VPC2 is no longer supported
  70  	DetachVPC2(ctx context.Context, instanceID, vpcID string) error
  71  }
  72  
  73  // InstanceServiceHandler handles interaction with the server methods for the Vultr API
  74  type InstanceServiceHandler struct {
  75  	client *Client
  76  }
  77  
  78  // Instance represents a VPS
  79  type Instance struct {
  80  	ID               string   `json:"id"`
  81  	Os               string   `json:"os"`
  82  	RAM              int      `json:"ram"`
  83  	Disk             int      `json:"disk"`
  84  	Plan             string   `json:"plan"`
  85  	MainIP           string   `json:"main_ip"`
  86  	VPCOnly          bool     `json:"vpc_only"`
  87  	VCPUCount        int      `json:"vcpu_count"`
  88  	Region           string   `json:"region"`
  89  	DefaultPassword  string   `json:"default_password,omitempty"`
  90  	DateCreated      string   `json:"date_created"`
  91  	Status           string   `json:"status"`
  92  	AllowedBandwidth int      `json:"allowed_bandwidth"`
  93  	NetmaskV4        string   `json:"netmask_v4"`
  94  	GatewayV4        string   `json:"gateway_v4"`
  95  	PowerStatus      string   `json:"power_status"`
  96  	ServerStatus     string   `json:"server_status"`
  97  	V6Network        string   `json:"v6_network"`
  98  	V6MainIP         string   `json:"v6_main_ip"`
  99  	V6NetworkSize    int      `json:"v6_network_size"`
 100  	Label            string   `json:"label"`
 101  	InternalIP       string   `json:"internal_ip"`
 102  	KVM              string   `json:"kvm"`
 103  	OsID             int      `json:"os_id"`
 104  	AppID            int      `json:"app_id"`
 105  	ImageID          string   `json:"image_id"`
 106  	SnapshotID       string   `json:"snapshot_id"`
 107  	FirewallGroupID  string   `json:"firewall_group_id"`
 108  	Features         []string `json:"features"`
 109  	Hostname         string   `json:"hostname"`
 110  	Tags             []string `json:"tags"`
 111  	UserScheme       string   `json:"user_scheme"`
 112  }
 113  
 114  type instanceBase struct {
 115  	Instance *Instance `json:"instance"`
 116  }
 117  
 118  type ipv4Base struct {
 119  	IPv4 *IPv4 `json:"ipv4"`
 120  }
 121  
 122  type instancesBase struct {
 123  	Instances []Instance `json:"instances"`
 124  	Meta      *Meta      `json:"meta"`
 125  }
 126  
 127  // Neighbors that might exist on the same host.
 128  type Neighbors struct {
 129  	Neighbors []string `json:"neighbors"`
 130  }
 131  
 132  // Bandwidth used on a given instance.
 133  type Bandwidth struct {
 134  	Bandwidth map[string]struct {
 135  		IncomingBytes int `json:"incoming_bytes"`
 136  		OutgoingBytes int `json:"outgoing_bytes"`
 137  	} `json:"bandwidth"`
 138  }
 139  
 140  type vpcInfoBase struct {
 141  	VPCs []VPCInfo `json:"vpcs"`
 142  	Meta *Meta     `json:"meta"`
 143  }
 144  
 145  // VPCInfo information for a given instance.
 146  type VPCInfo struct {
 147  	ID         string `json:"id"`
 148  	MacAddress string `json:"mac_address"`
 149  	IPAddress  string `json:"ip_address"`
 150  }
 151  
 152  type vpc2InfoBase struct {
 153  	VPCs []VPC2Info `json:"vpcs"`
 154  	Meta *Meta      `json:"meta"`
 155  }
 156  
 157  // VPC2Info information for a given instance.
 158  //
 159  // Deprecated: VPC2 is no longer supported
 160  type VPC2Info struct {
 161  	ID         string `json:"id"`
 162  	MacAddress string `json:"mac_address"`
 163  	IPAddress  string `json:"ip_address"`
 164  }
 165  
 166  // AttachVPC2Req parameters for attaching a VPC 2.0 network
 167  //
 168  // Deprecated: VPC2 is no longer supported
 169  type AttachVPC2Req struct {
 170  	VPCID     string  `json:"vpc_id,omitempty"`
 171  	IPAddress *string `json:"ip_address,omitempty"`
 172  }
 173  
 174  type isoStatusBase struct {
 175  	IsoStatus *Iso `json:"iso_status"`
 176  }
 177  
 178  // Iso information for a given instance.
 179  type Iso struct {
 180  	State string `json:"state"`
 181  	IsoID string `json:"iso_id"`
 182  }
 183  
 184  type backupScheduleBase struct {
 185  	BackupSchedule *BackupSchedule `json:"backup_schedule"`
 186  }
 187  
 188  // BackupSchedule information for a given instance.
 189  type BackupSchedule struct {
 190  	Enabled             *bool  `json:"enabled,omitempty"`
 191  	Type                string `json:"type,omitempty"`
 192  	NextScheduleTimeUTC string `json:"next_scheduled_time_utc,omitempty"`
 193  	Hour                int    `json:"hour,omitempty"`
 194  	Dow                 int    `json:"dow,omitempty"`
 195  	Dom                 int    `json:"dom,omitempty"`
 196  }
 197  
 198  // BackupScheduleReq struct used to create a backup schedule for an instance.
 199  type BackupScheduleReq struct {
 200  	Type string `json:"type"`
 201  	Hour *int   `json:"hour,omitempty"`
 202  	Dow  *int   `json:"dow,omitempty"`
 203  	Dom  int    `json:"dom,omitempty"`
 204  }
 205  
 206  // RestoreReq struct used to supply whether a restore should be from a backup or snapshot.
 207  type RestoreReq struct {
 208  	BackupID   string `json:"backup_id,omitempty"`
 209  	SnapshotID string `json:"snapshot_id,omitempty"`
 210  }
 211  
 212  // todo can we remove this list and return this data back in the list?
 213  type reverseIPv6sBase struct {
 214  	ReverseIPv6s []ReverseIP `json:"reverse_ipv6s"`
 215  	// no meta?
 216  }
 217  
 218  // ReverseIP information for a given instance.
 219  type ReverseIP struct {
 220  	IP      string `json:"ip"`
 221  	Reverse string `json:"reverse"`
 222  }
 223  
 224  type userDataBase struct {
 225  	UserData *UserData `json:"user_data"`
 226  }
 227  
 228  // UserData information for a given struct.
 229  type UserData struct {
 230  	Data string `json:"data"`
 231  }
 232  
 233  type upgradeBase struct {
 234  	Upgrades *Upgrades `json:"upgrades"`
 235  }
 236  
 237  // Upgrades that are available for a given Instance.
 238  type Upgrades struct {
 239  	Applications []Application `json:"applications,omitempty"`
 240  	OS           []OS          `json:"os,omitempty"`
 241  	Plans        []string      `json:"plans,omitempty"`
 242  }
 243  
 244  // InstanceCreateReq struct used to create an instance.
 245  type InstanceCreateReq struct {
 246  	Region            string   `json:"region,omitempty"`
 247  	Plan              string   `json:"plan,omitempty"`
 248  	Label             string   `json:"label,omitempty"`
 249  	Tags              []string `json:"tags"`
 250  	OsID              int      `json:"os_id,omitempty"`
 251  	ISOID             string   `json:"iso_id,omitempty"`
 252  	AppID             int      `json:"app_id,omitempty"`
 253  	ImageID           string   `json:"image_id,omitempty"`
 254  	FirewallGroupID   string   `json:"firewall_group_id,omitempty"`
 255  	Hostname          string   `json:"hostname,omitempty"`
 256  	IPXEChainURL      string   `json:"ipxe_chain_url,omitempty"`
 257  	ScriptID          string   `json:"script_id,omitempty"`
 258  	SnapshotID        string   `json:"snapshot_id,omitempty"`
 259  	EnableIPv6        *bool    `json:"enable_ipv6,omitempty"`
 260  	DisablePublicIPv4 *bool    `json:"disable_public_ipv4,omitempty"`
 261  	EnableVPC         *bool    `json:"enable_vpc,omitempty"`
 262  	AttachVPC         []string `json:"attach_vpc,omitempty"`
 263  	VPCOnly           *bool    `json:"vpc_only,omitempty"`
 264  
 265  	SSHKeys         []string          `json:"sshkey_id,omitempty"`
 266  	Backups         string            `json:"backups,omitempty"`
 267  	DDOSProtection  *bool             `json:"ddos_protection,omitempty"`
 268  	UserData        string            `json:"user_data,omitempty"`
 269  	ReservedIPv4    string            `json:"reserved_ipv4,omitempty"`
 270  	ActivationEmail *bool             `json:"activation_email,omitempty"`
 271  	UserScheme      string            `json:"user_scheme,omitempty"`
 272  	AppVariables    map[string]string `json:"app_variables,omitempty"`
 273  
 274  	// Deprecated: VPC2 is no longer supported
 275  	EnableVPC2 *bool `json:"enable_vpc2,omitempty"`
 276  
 277  	// Deprecated: VPC2 is no longer supported
 278  	AttachVPC2 []string `json:"attach_vpc2,omitempty"`
 279  }
 280  
 281  // InstanceUpdateReq struct used to update an instance.
 282  type InstanceUpdateReq struct {
 283  	Plan            string   `json:"plan,omitempty"`
 284  	Label           string   `json:"label,omitempty"`
 285  	Tags            []string `json:"tags"`
 286  	OsID            int      `json:"os_id,omitempty"`
 287  	AppID           int      `json:"app_id,omitempty"`
 288  	ImageID         string   `json:"image_id,omitempty"`
 289  	EnableIPv6      *bool    `json:"enable_ipv6,omitempty"`
 290  	EnableVPC       *bool    `json:"enable_vpc,omitempty"`
 291  	AttachVPC       []string `json:"attach_vpc,omitempty"`
 292  	DetachVPC       []string `json:"detach_vpc,omitempty"`
 293  	Backups         string   `json:"backups,omitempty"`
 294  	DDOSProtection  *bool    `json:"ddos_protection"`
 295  	UserData        string   `json:"user_data,omitempty"`
 296  	FirewallGroupID string   `json:"firewall_group_id,omitempty"`
 297  	UserScheme      string   `json:"user_scheme,omitempty"`
 298  
 299  	// Deprecated: VPC2 is no longer supported
 300  	EnableVPC2 *bool `json:"enable_vpc2,omitempty"`
 301  
 302  	// Deprecated: VPC2 is no longer supported
 303  	AttachVPC2 []string `json:"attach_vpc2,omitempty"`
 304  
 305  	// Deprecated: VPC2 is no longer supported
 306  	DetachVPC2 []string `json:"detach_vpc2,omitempty"`
 307  }
 308  
 309  // ReinstallReq struct used to allow changes during a reinstall
 310  type ReinstallReq struct {
 311  	Hostname string `json:"hostname,omitempty"`
 312  }
 313  
 314  // Create will create the server with the given parameters
 315  func (i *InstanceServiceHandler) Create(ctx context.Context, instanceReq *InstanceCreateReq) (*Instance, *http.Response, error) {
 316  	req, err := i.client.NewRequest(ctx, http.MethodPost, instancePath, instanceReq)
 317  	if err != nil {
 318  		return nil, nil, err
 319  	}
 320  
 321  	instance := new(instanceBase)
 322  	resp, err := i.client.DoWithContext(ctx, req, instance)
 323  	if err != nil {
 324  		return nil, resp, err
 325  	}
 326  
 327  	return instance.Instance, resp, nil
 328  }
 329  
 330  // Get will get the server with the given instanceID
 331  func (i *InstanceServiceHandler) Get(ctx context.Context, instanceID string) (*Instance, *http.Response, error) {
 332  	uri := fmt.Sprintf("%s/%s", instancePath, instanceID)
 333  
 334  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 335  	if err != nil {
 336  		return nil, nil, err
 337  	}
 338  
 339  	instance := new(instanceBase)
 340  	resp, err := i.client.DoWithContext(ctx, req, instance)
 341  	if err != nil {
 342  		return nil, resp, err
 343  	}
 344  
 345  	return instance.Instance, resp, nil
 346  }
 347  
 348  // Update will update the server with the given parameters
 349  func (i *InstanceServiceHandler) Update(ctx context.Context, instanceID string, instanceReq *InstanceUpdateReq) (*Instance, *http.Response, error) { //nolint:lll
 350  	uri := fmt.Sprintf("%s/%s", instancePath, instanceID)
 351  
 352  	req, err := i.client.NewRequest(ctx, http.MethodPatch, uri, instanceReq)
 353  	if err != nil {
 354  		return nil, nil, err
 355  	}
 356  
 357  	instance := new(instanceBase)
 358  	resp, err := i.client.DoWithContext(ctx, req, instance)
 359  	if err != nil {
 360  		return nil, resp, err
 361  	}
 362  
 363  	return instance.Instance, resp, nil
 364  }
 365  
 366  // Delete an instance. All data will be permanently lost, and the IP address will be released
 367  func (i *InstanceServiceHandler) Delete(ctx context.Context, instanceID string) error {
 368  	uri := fmt.Sprintf("%s/%s", instancePath, instanceID)
 369  
 370  	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 371  	if err != nil {
 372  		return err
 373  	}
 374  
 375  	_, err = i.client.DoWithContext(ctx, req, nil)
 376  	return err
 377  }
 378  
 379  // List all instances on your account.
 380  func (i *InstanceServiceHandler) List(ctx context.Context, options *ListOptions) ([]Instance, *Meta, *http.Response, error) { //nolint:dupl
 381  	req, err := i.client.NewRequest(ctx, http.MethodGet, instancePath, nil)
 382  	if err != nil {
 383  		return nil, nil, nil, err
 384  	}
 385  
 386  	newValues, err := query.Values(options)
 387  	if err != nil {
 388  		return nil, nil, nil, err
 389  	}
 390  
 391  	req.URL.RawQuery = newValues.Encode()
 392  
 393  	instances := new(instancesBase)
 394  	resp, err := i.client.DoWithContext(ctx, req, instances)
 395  	if err != nil {
 396  		return nil, nil, resp, err
 397  	}
 398  
 399  	return instances.Instances, instances.Meta, resp, nil
 400  }
 401  
 402  // Start will start a vps instance the machine is already running, it will be restarted.
 403  func (i *InstanceServiceHandler) Start(ctx context.Context, instanceID string) error {
 404  	uri := fmt.Sprintf("%s/%s/start", instancePath, instanceID)
 405  
 406  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
 407  	if err != nil {
 408  		return err
 409  	}
 410  	_, err = i.client.DoWithContext(ctx, req, nil)
 411  	return err
 412  }
 413  
 414  // Halt will pause an instance.
 415  func (i *InstanceServiceHandler) Halt(ctx context.Context, instanceID string) error {
 416  	uri := fmt.Sprintf("%s/%s/halt", instancePath, instanceID)
 417  
 418  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
 419  	if err != nil {
 420  		return err
 421  	}
 422  	_, err = i.client.DoWithContext(ctx, req, nil)
 423  	return err
 424  }
 425  
 426  // Reboot an instance.
 427  func (i *InstanceServiceHandler) Reboot(ctx context.Context, instanceID string) error {
 428  	uri := fmt.Sprintf("%s/%s/reboot", instancePath, instanceID)
 429  
 430  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
 431  	if err != nil {
 432  		return err
 433  	}
 434  	_, err = i.client.DoWithContext(ctx, req, nil)
 435  	return err
 436  }
 437  
 438  // Reinstall an instance.
 439  func (i *InstanceServiceHandler) Reinstall(ctx context.Context, instanceID string, reinstallReq *ReinstallReq) (*Instance, *http.Response, error) { //nolint:lll
 440  	uri := fmt.Sprintf("%s/%s/reinstall", instancePath, instanceID)
 441  
 442  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reinstallReq)
 443  	if err != nil {
 444  		return nil, nil, err
 445  	}
 446  
 447  	instance := new(instanceBase)
 448  	resp, err := i.client.DoWithContext(ctx, req, instance)
 449  	if err != nil {
 450  		return nil, resp, err
 451  	}
 452  	return instance.Instance, resp, nil
 453  }
 454  
 455  // MassStart will start a list of instances the machine is already running, it will be restarted.
 456  func (i *InstanceServiceHandler) MassStart(ctx context.Context, instanceList []string) error {
 457  	uri := fmt.Sprintf("%s/start", instancePath)
 458  
 459  	reqBody := RequestBody{"instance_ids": instanceList}
 460  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 461  	if err != nil {
 462  		return err
 463  	}
 464  	_, err = i.client.DoWithContext(ctx, req, nil)
 465  	return err
 466  }
 467  
 468  // MassHalt will pause a list of instances.
 469  func (i *InstanceServiceHandler) MassHalt(ctx context.Context, instanceList []string) error {
 470  	uri := fmt.Sprintf("%s/halt", instancePath)
 471  
 472  	reqBody := RequestBody{"instance_ids": instanceList}
 473  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 474  	if err != nil {
 475  		return err
 476  	}
 477  	_, err = i.client.DoWithContext(ctx, req, nil)
 478  	return err
 479  }
 480  
 481  // MassReboot reboots a list of instances.
 482  func (i *InstanceServiceHandler) MassReboot(ctx context.Context, instanceList []string) error {
 483  	uri := fmt.Sprintf("%s/reboot", instancePath)
 484  
 485  	reqBody := RequestBody{"instance_ids": instanceList}
 486  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 487  	if err != nil {
 488  		return err
 489  	}
 490  	_, err = i.client.DoWithContext(ctx, req, nil)
 491  	return err
 492  }
 493  
 494  // Restore an instance.
 495  func (i *InstanceServiceHandler) Restore(ctx context.Context, instanceID string, restoreReq *RestoreReq) (*http.Response, error) {
 496  	uri := fmt.Sprintf("%s/%s/restore", instancePath, instanceID)
 497  
 498  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, restoreReq)
 499  	if err != nil {
 500  		return nil, err
 501  	}
 502  
 503  	return i.client.DoWithContext(ctx, req, nil)
 504  }
 505  
 506  // GetBandwidth for a given instance.
 507  func (i *InstanceServiceHandler) GetBandwidth(ctx context.Context, instanceID string) (*Bandwidth, *http.Response, error) {
 508  	uri := fmt.Sprintf("%s/%s/bandwidth", instancePath, instanceID)
 509  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 510  	if err != nil {
 511  		return nil, nil, err
 512  	}
 513  
 514  	bandwidth := new(Bandwidth)
 515  	resp, err := i.client.DoWithContext(ctx, req, bandwidth)
 516  	if err != nil {
 517  		return nil, resp, err
 518  	}
 519  
 520  	return bandwidth, resp, nil
 521  }
 522  
 523  // GetNeighbors gets a list of other instances in the same location as this Instance.
 524  func (i *InstanceServiceHandler) GetNeighbors(ctx context.Context, instanceID string) (*Neighbors, *http.Response, error) {
 525  	uri := fmt.Sprintf("%s/%s/neighbors", instancePath, instanceID)
 526  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 527  	if err != nil {
 528  		return nil, nil, err
 529  	}
 530  
 531  	neighbors := new(Neighbors)
 532  	resp, err := i.client.DoWithContext(ctx, req, neighbors)
 533  	if err != nil {
 534  		return nil, resp, err
 535  	}
 536  
 537  	return neighbors, resp, nil
 538  }
 539  
 540  // ListVPCInfo currently attached to an instance.
 541  func (i *InstanceServiceHandler) ListVPCInfo(ctx context.Context, instanceID string, options *ListOptions) ([]VPCInfo, *Meta, *http.Response, error) { //nolint:lll,dupl
 542  	uri := fmt.Sprintf("%s/%s/vpcs", instancePath, instanceID)
 543  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 544  	if err != nil {
 545  		return nil, nil, nil, err
 546  	}
 547  
 548  	newValues, err := query.Values(options)
 549  	if err != nil {
 550  		return nil, nil, nil, err
 551  	}
 552  
 553  	req.URL.RawQuery = newValues.Encode()
 554  
 555  	vpcs := new(vpcInfoBase)
 556  	resp, err := i.client.DoWithContext(ctx, req, vpcs)
 557  	if err != nil {
 558  		return nil, nil, resp, err
 559  	}
 560  
 561  	return vpcs.VPCs, vpcs.Meta, resp, nil
 562  }
 563  
 564  // AttachVPC to an instance
 565  func (i *InstanceServiceHandler) AttachVPC(ctx context.Context, instanceID, vpcID string) error {
 566  	uri := fmt.Sprintf("%s/%s/vpcs/attach", instancePath, instanceID)
 567  	body := RequestBody{"vpc_id": vpcID}
 568  
 569  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
 570  	if err != nil {
 571  		return err
 572  	}
 573  
 574  	_, err = i.client.DoWithContext(ctx, req, nil)
 575  	return err
 576  }
 577  
 578  // DetachVPC from an instance.
 579  func (i *InstanceServiceHandler) DetachVPC(ctx context.Context, instanceID, vpcID string) error {
 580  	uri := fmt.Sprintf("%s/%s/vpcs/detach", instancePath, instanceID)
 581  	body := RequestBody{"vpc_id": vpcID}
 582  
 583  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
 584  	if err != nil {
 585  		return err
 586  	}
 587  	_, err = i.client.DoWithContext(ctx, req, nil)
 588  	return err
 589  }
 590  
 591  // ListVPC2Info currently attached to an instance.
 592  //
 593  // Deprecated: VPC2 is no longer supported
 594  func (i *InstanceServiceHandler) ListVPC2Info(ctx context.Context, instanceID string, options *ListOptions) ([]VPC2Info, *Meta, *http.Response, error) { //nolint:lll,dupl
 595  	uri := fmt.Sprintf("%s/%s/vpc2", instancePath, instanceID)
 596  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 597  	if err != nil {
 598  		return nil, nil, nil, err
 599  	}
 600  
 601  	newValues, err := query.Values(options)
 602  	if err != nil {
 603  		return nil, nil, nil, err
 604  	}
 605  
 606  	req.URL.RawQuery = newValues.Encode()
 607  
 608  	vpcs := new(vpc2InfoBase)
 609  	resp, err := i.client.DoWithContext(ctx, req, vpcs)
 610  	if err != nil {
 611  		return nil, nil, resp, err
 612  	}
 613  
 614  	return vpcs.VPCs, vpcs.Meta, resp, nil
 615  }
 616  
 617  // AttachVPC2 to an instance
 618  //
 619  // Deprecated: VPC2 is no longer supported
 620  func (i *InstanceServiceHandler) AttachVPC2(ctx context.Context, instanceID string, vpc2Req *AttachVPC2Req) error {
 621  	uri := fmt.Sprintf("%s/%s/vpc2/attach", instancePath, instanceID)
 622  
 623  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, vpc2Req)
 624  	if err != nil {
 625  		return err
 626  	}
 627  
 628  	_, err = i.client.DoWithContext(ctx, req, nil)
 629  	return err
 630  }
 631  
 632  // DetachVPC2 from an instance.
 633  //
 634  // Deprecated: VPC2 is no longer supported
 635  func (i *InstanceServiceHandler) DetachVPC2(ctx context.Context, instanceID, vpcID string) error {
 636  	uri := fmt.Sprintf("%s/%s/vpc2/detach", instancePath, instanceID)
 637  	body := RequestBody{"vpc_id": vpcID}
 638  
 639  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
 640  	if err != nil {
 641  		return err
 642  	}
 643  
 644  	_, err = i.client.DoWithContext(ctx, req, nil)
 645  	return err
 646  }
 647  
 648  // ISOStatus retrieves the current ISO state for a given VPS.
 649  // The returned state may be one of: ready | isomounting | isomounted.
 650  func (i *InstanceServiceHandler) ISOStatus(ctx context.Context, instanceID string) (*Iso, *http.Response, error) {
 651  	uri := fmt.Sprintf("%s/%s/iso", instancePath, instanceID)
 652  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 653  	if err != nil {
 654  		return nil, nil, err
 655  	}
 656  
 657  	iso := new(isoStatusBase)
 658  	resp, err := i.client.DoWithContext(ctx, req, iso)
 659  	if err != nil {
 660  		return nil, resp, err
 661  	}
 662  	return iso.IsoStatus, resp, nil
 663  }
 664  
 665  // AttachISO will attach an ISO to the given instance and reboot it
 666  func (i *InstanceServiceHandler) AttachISO(ctx context.Context, instanceID, isoID string) (*http.Response, error) {
 667  	uri := fmt.Sprintf("%s/%s/iso/attach", instancePath, instanceID)
 668  	body := RequestBody{"iso_id": isoID}
 669  
 670  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
 671  	if err != nil {
 672  		return nil, err
 673  	}
 674  
 675  	return i.client.DoWithContext(ctx, req, nil)
 676  }
 677  
 678  // DetachISO will detach the currently mounted ISO and reboot the instance.
 679  func (i *InstanceServiceHandler) DetachISO(ctx context.Context, instanceID string) (*http.Response, error) {
 680  	uri := fmt.Sprintf("%s/%s/iso/detach", instancePath, instanceID)
 681  
 682  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
 683  	if err != nil {
 684  		return nil, err
 685  	}
 686  
 687  	return i.client.DoWithContext(ctx, req, nil)
 688  }
 689  
 690  // GetBackupSchedule retrieves the backup schedule for a given instance - all time values are in UTC
 691  func (i *InstanceServiceHandler) GetBackupSchedule(ctx context.Context, instanceID string) (*BackupSchedule, *http.Response, error) {
 692  	uri := fmt.Sprintf("%s/%s/backup-schedule", instancePath, instanceID)
 693  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 694  	if err != nil {
 695  		return nil, nil, err
 696  	}
 697  
 698  	backup := new(backupScheduleBase)
 699  	resp, err := i.client.DoWithContext(ctx, req, backup)
 700  	if err != nil {
 701  		return nil, resp, err
 702  	}
 703  
 704  	return backup.BackupSchedule, resp, nil
 705  }
 706  
 707  // SetBackupSchedule sets the backup schedule for a given instance - all time values are in UTC.
 708  func (i *InstanceServiceHandler) SetBackupSchedule(ctx context.Context, instanceID string, backup *BackupScheduleReq) (*http.Response, error) { //nolint:lll
 709  	uri := fmt.Sprintf("%s/%s/backup-schedule", instancePath, instanceID)
 710  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, backup)
 711  	if err != nil {
 712  		return nil, err
 713  	}
 714  
 715  	return i.client.DoWithContext(ctx, req, nil)
 716  }
 717  
 718  // CreateIPv4 an additional IPv4 address for given instance.
 719  func (i *InstanceServiceHandler) CreateIPv4(ctx context.Context, instanceID string, reboot *bool) (*IPv4, *http.Response, error) {
 720  	uri := fmt.Sprintf("%s/%s/ipv4", instancePath, instanceID)
 721  
 722  	body := RequestBody{"reboot": reboot}
 723  
 724  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
 725  	if err != nil {
 726  		return nil, nil, err
 727  	}
 728  
 729  	ip := new(ipv4Base)
 730  	resp, err := i.client.DoWithContext(ctx, req, ip)
 731  	if err != nil {
 732  		return nil, resp, err
 733  	}
 734  
 735  	return ip.IPv4, resp, nil
 736  }
 737  
 738  // ListIPv4 addresses that are currently assigned to a given instance.
 739  func (i *InstanceServiceHandler) ListIPv4(ctx context.Context, instanceID string, options *ListOptions) ([]IPv4, *Meta, *http.Response, error) { //nolint:lll,dupl
 740  	uri := fmt.Sprintf("%s/%s/ipv4", instancePath, instanceID)
 741  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 742  	if err != nil {
 743  		return nil, nil, nil, err
 744  	}
 745  
 746  	newValues, err := query.Values(options)
 747  	if err != nil {
 748  		return nil, nil, nil, err
 749  	}
 750  
 751  	req.URL.RawQuery = newValues.Encode()
 752  	ips := new(ipBase)
 753  	resp, err := i.client.DoWithContext(ctx, req, ips)
 754  	if err != nil {
 755  		return nil, nil, resp, err
 756  	}
 757  
 758  	return ips.IPv4s, ips.Meta, resp, nil
 759  }
 760  
 761  // DeleteIPv4 address from a given instance.
 762  func (i *InstanceServiceHandler) DeleteIPv4(ctx context.Context, instanceID, ip string) error {
 763  	uri := fmt.Sprintf("%s/%s/ipv4/%s", instancePath, instanceID, ip)
 764  	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 765  	if err != nil {
 766  		return err
 767  	}
 768  
 769  	_, err = i.client.DoWithContext(ctx, req, nil)
 770  	return err
 771  }
 772  
 773  // ListIPv6 addresses that are currently assigned to a given instance.
 774  func (i *InstanceServiceHandler) ListIPv6(ctx context.Context, instanceID string, options *ListOptions) ([]IPv6, *Meta, *http.Response, error) { //nolint:lll,dupl
 775  	uri := fmt.Sprintf("%s/%s/ipv6", instancePath, instanceID)
 776  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 777  	if err != nil {
 778  		return nil, nil, nil, err
 779  	}
 780  
 781  	newValues, err := query.Values(options)
 782  	if err != nil {
 783  		return nil, nil, nil, err
 784  	}
 785  
 786  	req.URL.RawQuery = newValues.Encode()
 787  	ips := new(ipBase)
 788  	resp, err := i.client.DoWithContext(ctx, req, ips)
 789  	if err != nil {
 790  		return nil, nil, resp, err
 791  	}
 792  
 793  	return ips.IPv6s, ips.Meta, resp, nil
 794  }
 795  
 796  // CreateReverseIPv6 for a given instance.
 797  func (i *InstanceServiceHandler) CreateReverseIPv6(ctx context.Context, instanceID string, reverseReq *ReverseIP) error {
 798  	uri := fmt.Sprintf("%s/%s/ipv6/reverse", instancePath, instanceID)
 799  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reverseReq)
 800  	if err != nil {
 801  		return err
 802  	}
 803  	_, err = i.client.DoWithContext(ctx, req, nil)
 804  	return err
 805  }
 806  
 807  // ListReverseIPv6 currently assigned to a given instance.
 808  func (i *InstanceServiceHandler) ListReverseIPv6(ctx context.Context, instanceID string) ([]ReverseIP, *http.Response, error) {
 809  	uri := fmt.Sprintf("%s/%s/ipv6/reverse", instancePath, instanceID)
 810  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 811  	if err != nil {
 812  		return nil, nil, err
 813  	}
 814  
 815  	reverse := new(reverseIPv6sBase)
 816  	resp, err := i.client.DoWithContext(ctx, req, reverse)
 817  	if err != nil {
 818  		return nil, resp, err
 819  	}
 820  
 821  	return reverse.ReverseIPv6s, resp, nil
 822  }
 823  
 824  // DeleteReverseIPv6 a given reverse IPv6.
 825  func (i *InstanceServiceHandler) DeleteReverseIPv6(ctx context.Context, instanceID, ip string) error {
 826  	uri := fmt.Sprintf("%s/%s/ipv6/reverse/%s", instancePath, instanceID, ip)
 827  	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 828  	if err != nil {
 829  		return err
 830  	}
 831  	_, err = i.client.DoWithContext(ctx, req, nil)
 832  	return err
 833  }
 834  
 835  // CreateReverseIPv4 for a given IP on a given instance.
 836  func (i *InstanceServiceHandler) CreateReverseIPv4(ctx context.Context, instanceID string, reverseReq *ReverseIP) error {
 837  	uri := fmt.Sprintf("%s/%s/ipv4/reverse", instancePath, instanceID)
 838  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reverseReq)
 839  	if err != nil {
 840  		return err
 841  	}
 842  	_, err = i.client.DoWithContext(ctx, req, nil)
 843  	return err
 844  }
 845  
 846  // DefaultReverseIPv4 will set the IPs reverse setting back to the original one supplied by Vultr.
 847  func (i *InstanceServiceHandler) DefaultReverseIPv4(ctx context.Context, instanceID, ip string) error {
 848  	uri := fmt.Sprintf("%s/%s/ipv4/reverse/default", instancePath, instanceID)
 849  	reqBody := RequestBody{"ip": ip}
 850  
 851  	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 852  	if err != nil {
 853  		return err
 854  	}
 855  	_, err = i.client.DoWithContext(ctx, req, nil)
 856  	return err
 857  }
 858  
 859  // GetUserData from given instance. The userdata returned will be in base64 encoding.
 860  func (i *InstanceServiceHandler) GetUserData(ctx context.Context, instanceID string) (*UserData, *http.Response, error) {
 861  	uri := fmt.Sprintf("%s/%s/user-data", instancePath, instanceID)
 862  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 863  	if err != nil {
 864  		return nil, nil, err
 865  	}
 866  
 867  	userData := new(userDataBase)
 868  	resp, err := i.client.DoWithContext(ctx, req, userData)
 869  	if err != nil {
 870  		return nil, resp, err
 871  	}
 872  
 873  	return userData.UserData, resp, nil
 874  }
 875  
 876  // GetUpgrades that are available for a given instance.
 877  func (i *InstanceServiceHandler) GetUpgrades(ctx context.Context, instanceID string) (*Upgrades, *http.Response, error) {
 878  	uri := fmt.Sprintf("%s/%s/upgrades", instancePath, instanceID)
 879  	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 880  	if err != nil {
 881  		return nil, nil, err
 882  	}
 883  
 884  	upgrades := new(upgradeBase)
 885  	resp, err := i.client.DoWithContext(ctx, req, upgrades)
 886  	if err != nil {
 887  		return nil, resp, err
 888  	}
 889  
 890  	return upgrades.Upgrades, resp, nil
 891  }
 892