1package govultr
2
3import (
4	"context"
5	"fmt"
6	"net/http"
7
8	"github.com/google/go-querystring/query"
9)
10
11const ripPath = "/v2/reserved-ips"
12
13// ReservedIPService is the interface to interact with the reserved IP endpoints on the Vultr API
14// Link : https://www.vultr.com/api/#tag/reserved-ip
15type ReservedIPService interface {
16	Create(ctx context.Context, ripCreate *ReservedIPReq) (*ReservedIP, error)
17	Get(ctx context.Context, id string) (*ReservedIP, error)
18	Delete(ctx context.Context, id string) error
19	List(ctx context.Context, options *ListOptions) ([]ReservedIP, *Meta, error)
20
21	Convert(ctx context.Context, ripConvert *ReservedIPConvertReq) (*ReservedIP, error)
22	Attach(ctx context.Context, id, instance string) error
23	Detach(ctx context.Context, id string) error
24}
25
26// ReservedIPServiceHandler handles interaction with the reserved IP methods for the Vultr API
27type ReservedIPServiceHandler struct {
28	client *Client
29}
30
31// ReservedIP represents an reserved IP on Vultr
32type ReservedIP struct {
33	ID         string `json:"id"`
34	Region     string `json:"region"`
35	IPType     string `json:"ip_type"`
36	Subnet     string `json:"subnet"`
37	SubnetSize int    `json:"subnet_size"`
38	Label      string `json:"label"`
39	InstanceID string `json:"instance_id"`
40}
41
42// ReservedIPReq represents the parameters for creating a new Reserved IP on Vultr
43type ReservedIPReq struct {
44	Region     string `json:"region,omitempty"`
45	IPType     string `json:"ip_type,omitempty"`
46	IPAddress  string `json:"ip_address,omitempty"`
47	Label      string `json:"label,omitempty"`
48	InstanceID string `json:"instance_id,omitempty"`
49}
50
51type reservedIPsBase struct {
52	ReservedIPs []ReservedIP `json:"reserved_ips"`
53	Meta        *Meta        `json:"meta"`
54}
55
56type reservedIPBase struct {
57	ReservedIP *ReservedIP `json:"reserved_ip"`
58}
59
60// ReservedIPConvertReq is the struct used for create and update calls.
61type ReservedIPConvertReq struct {
62	IPAddress string `json:"ip_address,omitempty"`
63	Label     string `json:"label,omitempty"`
64}
65
66// Create adds the specified reserved IP to your Vultr account
67func (r *ReservedIPServiceHandler) Create(ctx context.Context, ripCreate *ReservedIPReq) (*ReservedIP, error) {
68	req, err := r.client.NewRequest(ctx, http.MethodPost, ripPath, ripCreate)
69	if err != nil {
70		return nil, err
71	}
72
73	rip := new(reservedIPBase)
74	if err = r.client.DoWithContext(ctx, req, rip); err != nil {
75		return nil, err
76	}
77
78	return rip.ReservedIP, nil
79}
80
81// Get gets the reserved IP associated with provided ID
82func (r *ReservedIPServiceHandler) Get(ctx context.Context, id string) (*ReservedIP, error) {
83	uri := fmt.Sprintf("%s/%s", ripPath, id)
84	req, err := r.client.NewRequest(ctx, http.MethodGet, uri, nil)
85	if err != nil {
86		return nil, err
87	}
88
89	rip := new(reservedIPBase)
90	if err = r.client.DoWithContext(ctx, req, rip); err != nil {
91		return nil, err
92	}
93
94	return rip.ReservedIP, nil
95}
96
97// Delete removes the specified reserved IP from your Vultr account
98func (r *ReservedIPServiceHandler) Delete(ctx context.Context, id string) error {
99	uri := fmt.Sprintf("%s/%s", ripPath, id)
100	req, err := r.client.NewRequest(ctx, http.MethodDelete, uri, nil)
101	if err != nil {
102		return err
103	}
104
105	return r.client.DoWithContext(ctx, req, nil)
106}
107
108// List lists all the reserved IPs associated with your Vultr account
109func (r *ReservedIPServiceHandler) List(ctx context.Context, options *ListOptions) ([]ReservedIP, *Meta, error) {
110	req, err := r.client.NewRequest(ctx, http.MethodGet, ripPath, nil)
111	if err != nil {
112		return nil, nil, err
113	}
114
115	newValues, err := query.Values(options)
116	if err != nil {
117		return nil, nil, err
118	}
119
120	req.URL.RawQuery = newValues.Encode()
121
122	ips := new(reservedIPsBase)
123	if err = r.client.DoWithContext(ctx, req, ips); err != nil {
124		return nil, nil, err
125	}
126
127	return ips.ReservedIPs, ips.Meta, nil
128}
129
130// Convert an existing IP on a subscription to a reserved IP.
131func (r *ReservedIPServiceHandler) Convert(ctx context.Context, ripConvert *ReservedIPConvertReq) (*ReservedIP, error) {
132	uri := fmt.Sprintf("%s/convert", ripPath)
133	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, ripConvert)
134
135	if err != nil {
136		return nil, err
137	}
138
139	rip := new(reservedIPBase)
140	if err = r.client.DoWithContext(ctx, req, rip); err != nil {
141		return nil, err
142	}
143
144	return rip.ReservedIP, nil
145}
146
147// Attach a reserved IP to an existing subscription
148func (r *ReservedIPServiceHandler) Attach(ctx context.Context, id, instance string) error {
149	uri := fmt.Sprintf("%s/%s/attach", ripPath, id)
150	reqBody := RequestBody{"instance_id": instance}
151	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
152	if err != nil {
153		return err
154	}
155
156	return r.client.DoWithContext(ctx, req, nil)
157}
158
159// Detach a reserved IP from an existing subscription.
160func (r *ReservedIPServiceHandler) Detach(ctx context.Context, id string) error {
161	uri := fmt.Sprintf("%s/%s/detach", ripPath, id)
162	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, nil)
163	if err != nil {
164		return err
165	}
166
167	return r.client.DoWithContext(ctx, req, nil)
168}
169