1package gsclient
2
3import (
4	"context"
5	"errors"
6	"net/http"
7	"path"
8)
9
10//ServerStorageRelationList JSON struct of a list of relations between a server and storages
11type ServerStorageRelationList struct {
12	//Array of relations between a server and storages
13	List []ServerStorageRelationProperties `json:"storage_relations"`
14}
15
16//ServerStorageRelationSingle JSON struct of a single relation between a server and a storage
17type ServerStorageRelationSingle struct {
18	//Properties of a relation between a server and a storage
19	Properties ServerStorageRelationProperties `json:"storage_relation"`
20}
21
22//ServerStorageRelationProperties JSON struct of properties of a relation between a server and a storage
23type ServerStorageRelationProperties struct {
24	//The UUID of an object is always unique, and refers to a specific object.
25	ObjectUUID string `json:"object_uuid"`
26
27	//The human-readable name of the object. It supports the full UTF-8 charset, with a maximum of 64 characters.
28	ObjectName string `json:"object_name"`
29
30	//The capacity of a storage/ISO-Image/template/snapshot in GB.
31	Capacity int `json:"capacity"`
32
33	//Indicates the speed of the storage. This may be (storage, storage_high or storage_insane).
34	StorageType string `json:"storage_type"`
35
36	//Defines the SCSI target ID. The SCSI defines transmission routes like Serial Attached SCSI (SAS), Fibre Channel and iSCSI.
37	//The target ID is a device (e.g. disk).
38	Target int `json:"target"`
39
40	//Is the common SCSI abbreviation of the Logical Unit Number. A LUN is a unique identifier for a single disk or a composite of disks.
41	Lun int `json:"lun"`
42
43	//Defines the SCSI controller id. The SCSI defines transmission routes such as Serial Attached SCSI (SAS), Fibre Channel and iSCSI.
44	Controller int `json:"controller"`
45
46	//Defines the date and time the object was initially created.
47	CreateTime GSTime `json:"create_time"`
48
49	//Defines if this object is the bootdevice. Storages, Networks and ISO-Images can have a bootdevice configured,
50	//but only one bootdevice per Storage, Network or ISO-Image.
51	//The boot order is as follows => Network > ISO-Image > Storage.
52	BootDevice bool `json:"bootdevice"`
53
54	//The SCSI bus id. The SCSI defines transmission routes like Serial Attached SCSI (SAS), Fibre Channel and iSCSI.
55	//Each SCSI device is addressed via a specific number. Each SCSI bus can have multiple SCSI devices connected to it.
56	Bus int `json:"bus"`
57
58	//Indicates the UUID of the last used template on this storage (inherited from snapshots).
59	LastUsedTemplate string `json:"last_used_template"`
60
61	//If a template has been used that requires a license key (e.g. Windows Servers)
62	//this shows the product_no of the license (see the /prices endpoint for more details).
63	LicenseProductNo int `json:"license_product_no"`
64
65	//The same as the object_uuid.
66	ServerUUID string `json:"server_uuid"`
67}
68
69//ServerStorageRelationCreateRequest JSON struct of a request for creating a relation between a server and a storage
70type ServerStorageRelationCreateRequest struct {
71	//The UUID of the storage you are requesting. If server's hardware profile is default, nested, q35 or q35_nested,
72	//you are allowed to attached 8 servers. Only 2 storage are allowed to be attached to server with other hardware profile
73	ObjectUUID string `json:"object_uuid"`
74
75	//Whether the server will boot from this storage device or not. Optional.
76	BootDevice bool `json:"bootdevice,omitempty"`
77}
78
79//ServerStorageRelationUpdateRequest JSON struct of a request for updating a relation between a server and a storage
80type ServerStorageRelationUpdateRequest struct {
81	//The ordering of the network interfaces. Lower numbers have lower PCI-IDs. Optional.
82	Ordering int `json:"ordering,omitempty"`
83
84	//Whether the server boots from this network or not. Optional.
85	BootDevice bool `json:"bootdevice,omitempty"`
86
87	//Defines information about IP prefix spoof protection (it allows source traffic only from the IPv4/IPv4 network prefixes).
88	//If empty, it allow no IPv4/IPv6 source traffic. If set to null, l3security is disabled (default). Optional.
89	L3security []string `json:"l3security,omitempty"`
90}
91
92//GetServerStorageList gets a list of a specific server's storages
93//
94//See: https://gridscale.io/en//api-documentation/index.html#operation/getServerLinkedStorages
95func (c *Client) GetServerStorageList(ctx context.Context, id string) ([]ServerStorageRelationProperties, error) {
96	if !isValidUUID(id) {
97		return nil, errors.New("'id' is invalid")
98	}
99	r := gsRequest{
100		uri:                 path.Join(apiServerBase, id, "storages"),
101		method:              http.MethodGet,
102		skipCheckingRequest: true,
103	}
104	var response ServerStorageRelationList
105	err := r.execute(ctx, *c, &response)
106	return response.List, err
107}
108
109//GetServerStorage gets a storage of a specific server
110//
111//See: https://gridscale.io/en//api-documentation/index.html#operation/getServerLinkedStorage
112func (c *Client) GetServerStorage(ctx context.Context, serverID, storageID string) (ServerStorageRelationProperties, error) {
113	if !isValidUUID(serverID) || !isValidUUID(storageID) {
114		return ServerStorageRelationProperties{}, errors.New("'serverID' or 'storageID' is invalid")
115	}
116	r := gsRequest{
117		uri:                 path.Join(apiServerBase, serverID, "storages", storageID),
118		method:              http.MethodGet,
119		skipCheckingRequest: true,
120	}
121	var response ServerStorageRelationSingle
122	err := r.execute(ctx, *c, &response)
123	return response.Properties, err
124}
125
126//UpdateServerStorage updates a link between a storage and a server
127//
128//See: https://gridscale.io/en//api-documentation/index.html#operation/updateServerLinkedStorage
129func (c *Client) UpdateServerStorage(ctx context.Context, serverID, storageID string, body ServerStorageRelationUpdateRequest) error {
130	if !isValidUUID(serverID) || !isValidUUID(storageID) {
131		return errors.New("'serverID' or 'storageID' is invalid")
132	}
133	r := gsRequest{
134		uri:    path.Join(apiServerBase, serverID, "storages", storageID),
135		method: http.MethodPatch,
136		body:   body,
137	}
138	return r.execute(ctx, *c, nil)
139}
140
141//CreateServerStorage create a link between a server and a storage
142//
143//See: https://gridscale.io/en//api-documentation/index.html#operation/linkStorageToServer
144func (c *Client) CreateServerStorage(ctx context.Context, id string, body ServerStorageRelationCreateRequest) error {
145	if !isValidUUID(id) || !isValidUUID(body.ObjectUUID) {
146		return errors.New("'server_id' or 'storage_id' is invalid")
147	}
148	r := gsRequest{
149		uri:    path.Join(apiServerBase, id, "storages"),
150		method: http.MethodPost,
151		body:   body,
152	}
153	return r.execute(ctx, *c, nil)
154}
155
156//DeleteServerStorage delete a link between a storage and a server
157//
158//See: https://gridscale.io/en//api-documentation/index.html#operation/unlinkStorageFromServer
159func (c *Client) DeleteServerStorage(ctx context.Context, serverID, storageID string) error {
160	if !isValidUUID(serverID) || !isValidUUID(storageID) {
161		return errors.New("'serverID' or 'storageID' is invalid")
162	}
163	r := gsRequest{
164		uri:    path.Join(apiServerBase, serverID, "storages", storageID),
165		method: http.MethodDelete,
166	}
167	return r.execute(ctx, *c, nil)
168}
169
170//LinkStorage attaches a storage to a server
171func (c *Client) LinkStorage(ctx context.Context, serverID string, storageID string, bootdevice bool) error {
172	body := ServerStorageRelationCreateRequest{
173		ObjectUUID: storageID,
174		BootDevice: bootdevice,
175	}
176	return c.CreateServerStorage(ctx, serverID, body)
177}
178
179//UnlinkStorage remove a storage from a server
180func (c *Client) UnlinkStorage(ctx context.Context, serverID string, storageID string) error {
181	return c.DeleteServerStorage(ctx, serverID, storageID)
182}
183