lke_clusters.go raw
1 package linodego
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "time"
8
9 "github.com/linode/linodego/internal/parseabletime"
10 )
11
12 // LKEClusterStatus represents the status of an LKECluster
13 type LKEClusterStatus string
14
15 // LKEClusterStatus enums start with LKECluster
16 const (
17 LKEClusterReady LKEClusterStatus = "ready"
18 LKEClusterNotReady LKEClusterStatus = "not_ready"
19 )
20
21 type LKEClusterStackType string
22
23 const (
24 LKEClusterStackIPv4 LKEClusterStackType = "ipv4"
25 LKEClusterDualStack LKEClusterStackType = "ipv4-ipv6"
26 )
27
28 // LKECluster represents a LKECluster object
29 type LKECluster struct {
30 ID int `json:"id"`
31 Created *time.Time `json:"-"`
32 Updated *time.Time `json:"-"`
33 Label string `json:"label"`
34 Region string `json:"region"`
35 Status LKEClusterStatus `json:"status"`
36 K8sVersion string `json:"k8s_version"`
37 Tags []string `json:"tags"`
38 ControlPlane LKEClusterControlPlane `json:"control_plane"`
39
40 // NOTE: Tier may not currently be available to all users and can only be used with v4beta.
41 Tier string `json:"tier"`
42
43 // NOTE: APLEnabled is currently in beta and may only function with API version v4beta.
44 APLEnabled bool `json:"apl_enabled"`
45
46 // NOTE: SubnetID, VpcID, and StackType may not currently be available to all users and can only be used with v4beta.
47 SubnetID int `json:"subnet_id"`
48 VpcID int `json:"vpc_id"`
49 StackType LKEClusterStackType `json:"stack_type"`
50 }
51
52 // LKEClusterCreateOptions fields are those accepted by CreateLKECluster
53 type LKEClusterCreateOptions struct {
54 NodePools []LKENodePoolCreateOptions `json:"node_pools"`
55 Label string `json:"label"`
56 Region string `json:"region"`
57 K8sVersion string `json:"k8s_version"`
58 Tags []string `json:"tags,omitempty"`
59 ControlPlane *LKEClusterControlPlaneOptions `json:"control_plane,omitempty"`
60
61 // NOTE: Tier may not currently be available to all users and can only be used with v4beta.
62 Tier string `json:"tier,omitempty"`
63
64 // NOTE: APLEnabled is currently in beta and may only function with API version v4beta.
65 APLEnabled bool `json:"apl_enabled,omitempty"`
66
67 // NOTE: SubnetID, VpcID, and StackType may not currently be available to all users and can only be used with v4beta.
68 SubnetID *int `json:"subnet_id,omitempty"`
69 VpcID *int `json:"vpc_id,omitempty"`
70 StackType *LKEClusterStackType `json:"stack_type,omitempty"`
71 }
72
73 // LKEClusterUpdateOptions fields are those accepted by UpdateLKECluster
74 type LKEClusterUpdateOptions struct {
75 K8sVersion string `json:"k8s_version,omitempty"`
76 Label string `json:"label,omitempty"`
77 Tags *[]string `json:"tags,omitempty"`
78 ControlPlane *LKEClusterControlPlaneOptions `json:"control_plane,omitempty"`
79 }
80
81 // LKEClusterAPIEndpoint fields are those returned by ListLKEClusterAPIEndpoints
82 type LKEClusterAPIEndpoint struct {
83 Endpoint string `json:"endpoint"`
84 }
85
86 // LKEClusterKubeconfig fields are those returned by GetLKEClusterKubeconfig
87 type LKEClusterKubeconfig struct {
88 KubeConfig string `json:"kubeconfig"` // Base64-encoded Kubeconfig file for this Cluster.
89 }
90
91 // LKEClusterDashboard fields are those returned by GetLKEClusterDashboard
92 type LKEClusterDashboard struct {
93 URL string `json:"url"`
94 }
95
96 // LKEVersion fields are those returned by GetLKEVersion
97 type LKEVersion struct {
98 ID string `json:"id"`
99 }
100
101 // LKETierVersion fields are those returned by GetLKETierVersion
102 // NOTE: It may not currently be available to all users and can only be used with v4beta.
103 type LKETierVersion struct {
104 ID string `json:"id"`
105 Tier LKEVersionTier `json:"tier"`
106 }
107
108 // LKEVersionTier enums represents different LKE tiers
109 type LKEVersionTier string
110
111 // LKEVersionTier enums start with LKEVersion
112 const (
113 LKEVersionStandard LKEVersionTier = "standard"
114 LKEVersionEnterprise LKEVersionTier = "enterprise"
115 )
116
117 // LKEClusterRegenerateOptions fields are those accepted by RegenerateLKECluster
118 type LKEClusterRegenerateOptions struct {
119 KubeConfig bool `json:"kubeconfig"`
120 ServiceToken bool `json:"servicetoken"`
121 }
122
123 // UnmarshalJSON implements the json.Unmarshaler interface
124 func (i *LKECluster) UnmarshalJSON(b []byte) error {
125 type Mask LKECluster
126
127 p := struct {
128 *Mask
129
130 Created *parseabletime.ParseableTime `json:"created"`
131 Updated *parseabletime.ParseableTime `json:"updated"`
132 }{
133 Mask: (*Mask)(i),
134 }
135
136 if err := json.Unmarshal(b, &p); err != nil {
137 return err
138 }
139
140 i.Created = (*time.Time)(p.Created)
141 i.Updated = (*time.Time)(p.Updated)
142
143 return nil
144 }
145
146 // GetCreateOptions converts a LKECluster to LKEClusterCreateOptions for use in CreateLKECluster
147 func (i LKECluster) GetCreateOptions() (o LKEClusterCreateOptions) {
148 o.Label = i.Label
149 o.Region = i.Region
150 o.K8sVersion = i.K8sVersion
151 o.Tags = i.Tags
152
153 isHA := i.ControlPlane.HighAvailability
154
155 o.ControlPlane = &LKEClusterControlPlaneOptions{
156 HighAvailability: &isHA,
157 // ACL will not be populated in the control plane response
158 }
159
160 // @TODO copy NodePools?
161 return o
162 }
163
164 // GetUpdateOptions converts a LKECluster to LKEClusterUpdateOptions for use in UpdateLKECluster
165 func (i LKECluster) GetUpdateOptions() (o LKEClusterUpdateOptions) {
166 o.K8sVersion = i.K8sVersion
167 o.Label = i.Label
168 o.Tags = &i.Tags
169
170 isHA := i.ControlPlane.HighAvailability
171
172 o.ControlPlane = &LKEClusterControlPlaneOptions{
173 HighAvailability: &isHA,
174 // ACL will not be populated in the control plane response
175 }
176
177 return o
178 }
179
180 // ListLKEVersions lists the Kubernetes versions available through LKE. This endpoint is cached by default.
181 func (c *Client) ListLKEVersions(ctx context.Context, opts *ListOptions) ([]LKEVersion, error) {
182 e := "lke/versions"
183
184 endpoint, err := generateListCacheURL(e, opts)
185 if err != nil {
186 return nil, err
187 }
188
189 if result := c.getCachedResponse(endpoint); result != nil {
190 return result.([]LKEVersion), nil
191 }
192
193 response, err := getPaginatedResults[LKEVersion](ctx, c, e, opts)
194 if err != nil {
195 return nil, err
196 }
197
198 c.addCachedResponse(endpoint, response, &cacheExpiryTime)
199
200 return response, nil
201 }
202
203 // GetLKEVersion gets details about a specific LKE Version. This endpoint is cached by default.
204 func (c *Client) GetLKEVersion(ctx context.Context, version string) (*LKEVersion, error) {
205 e := formatAPIPath("lke/versions/%s", version)
206
207 if result := c.getCachedResponse(e); result != nil {
208 result := result.(LKEVersion)
209 return &result, nil
210 }
211
212 response, err := doGETRequest[LKEVersion](ctx, c, e)
213 if err != nil {
214 return nil, err
215 }
216
217 c.addCachedResponse(e, response, &cacheExpiryTime)
218
219 return response, nil
220 }
221
222 // ListLKETierVersions lists all Kubernetes versions available given tier through LKE.
223 // NOTE: This endpoint may not currently be available to all users and can only be used with v4beta.
224 func (c *Client) ListLKETierVersions(ctx context.Context, tier string, opts *ListOptions) ([]LKETierVersion, error) {
225 return getPaginatedResults[LKETierVersion](ctx, c, formatAPIPath("lke/tiers/%s/versions", tier), opts)
226 }
227
228 // GetLKETierVersion gets the details of a specific LKE tier version.
229 // NOTE: This endpoint may not currently be available to all users and can only be used with v4beta.
230 func (c *Client) GetLKETierVersion(ctx context.Context, tier string, versionID string) (*LKETierVersion, error) {
231 return doGETRequest[LKETierVersion](ctx, c, formatAPIPath("lke/tiers/%s/versions/%s", tier, versionID))
232 }
233
234 // ListLKEClusterAPIEndpoints gets the API Endpoint for the LKE Cluster specified
235 func (c *Client) ListLKEClusterAPIEndpoints(ctx context.Context, clusterID int, opts *ListOptions) ([]LKEClusterAPIEndpoint, error) {
236 return getPaginatedResults[LKEClusterAPIEndpoint](ctx, c, formatAPIPath("lke/clusters/%d/api-endpoints", clusterID), opts)
237 }
238
239 // ListLKEClusters lists LKEClusters
240 func (c *Client) ListLKEClusters(ctx context.Context, opts *ListOptions) ([]LKECluster, error) {
241 return getPaginatedResults[LKECluster](ctx, c, "lke/clusters", opts)
242 }
243
244 // GetLKECluster gets the lkeCluster with the provided ID
245 func (c *Client) GetLKECluster(ctx context.Context, clusterID int) (*LKECluster, error) {
246 e := formatAPIPath("lke/clusters/%d", clusterID)
247 return doGETRequest[LKECluster](ctx, c, e)
248 }
249
250 // CreateLKECluster creates a LKECluster
251 func (c *Client) CreateLKECluster(ctx context.Context, opts LKEClusterCreateOptions) (*LKECluster, error) {
252 return doPOSTRequest[LKECluster](ctx, c, "lke/clusters", opts)
253 }
254
255 // UpdateLKECluster updates the LKECluster with the specified id
256 func (c *Client) UpdateLKECluster(ctx context.Context, clusterID int, opts LKEClusterUpdateOptions) (*LKECluster, error) {
257 e := formatAPIPath("lke/clusters/%d", clusterID)
258 return doPUTRequest[LKECluster](ctx, c, e, opts)
259 }
260
261 // DeleteLKECluster deletes the LKECluster with the specified id
262 func (c *Client) DeleteLKECluster(ctx context.Context, clusterID int) error {
263 e := formatAPIPath("lke/clusters/%d", clusterID)
264 return doDELETERequest(ctx, c, e)
265 }
266
267 // GetLKEClusterKubeconfig gets the Kubeconfig for the LKE Cluster specified
268 func (c *Client) GetLKEClusterKubeconfig(ctx context.Context, clusterID int) (*LKEClusterKubeconfig, error) {
269 e := formatAPIPath("lke/clusters/%d/kubeconfig", clusterID)
270 return doGETRequest[LKEClusterKubeconfig](ctx, c, e)
271 }
272
273 // DeleteLKEClusterKubeconfig deletes the Kubeconfig for the LKE Cluster specified
274 func (c *Client) DeleteLKEClusterKubeconfig(ctx context.Context, clusterID int) error {
275 e := formatAPIPath("lke/clusters/%d/kubeconfig", clusterID)
276 return doDELETERequest(ctx, c, e)
277 }
278
279 // GetLKEClusterDashboard gets information about the dashboard for an LKE cluster
280 func (c *Client) GetLKEClusterDashboard(ctx context.Context, clusterID int) (*LKEClusterDashboard, error) {
281 e := formatAPIPath("lke/clusters/%d/dashboard", clusterID)
282 return doGETRequest[LKEClusterDashboard](ctx, c, e)
283 }
284
285 // RecycleLKEClusterNodes recycles all nodes in all pools of the specified LKE Cluster.
286 func (c *Client) RecycleLKEClusterNodes(ctx context.Context, clusterID int) error {
287 e := formatAPIPath("lke/clusters/%d/recycle", clusterID)
288 return doPOSTRequestNoRequestResponseBody(ctx, c, e)
289 }
290
291 // RegenerateLKECluster regenerates the Kubeconfig file and/or the service account token for the specified LKE Cluster.
292 func (c *Client) RegenerateLKECluster(ctx context.Context, clusterID int, opts LKEClusterRegenerateOptions) (*LKECluster, error) {
293 e := formatAPIPath("lke/clusters/%d/regenerate", clusterID)
294 return doPOSTRequest[LKECluster](ctx, c, e, opts)
295 }
296
297 // DeleteLKEClusterServiceToken deletes and regenerate the service account token for a Cluster.
298 func (c *Client) DeleteLKEClusterServiceToken(ctx context.Context, clusterID int) error {
299 e := formatAPIPath("lke/clusters/%d/servicetoken", clusterID)
300 return doDELETERequest(ctx, c, e)
301 }
302
303 // GetLKEClusterAPLConsoleURL gets the URL of this cluster's APL installation if this cluster is APL-enabled.
304 func (c *Client) GetLKEClusterAPLConsoleURL(ctx context.Context, clusterID int) (string, error) {
305 cluster, err := c.GetLKECluster(ctx, clusterID)
306 if err != nil {
307 return "", err
308 }
309
310 if cluster.APLEnabled {
311 return fmt.Sprintf("https://console.lke%d.akamai-apl.net", cluster.ID), nil
312 }
313
314 return "", nil
315 }
316
317 // GetLKEClusterAPLHealthCheckURL gets the URL of this cluster's APL health check endpoint if this cluster is APL-enabled.
318 func (c *Client) GetLKEClusterAPLHealthCheckURL(ctx context.Context, clusterID int) (string, error) {
319 cluster, err := c.GetLKECluster(ctx, clusterID)
320 if err != nil {
321 return "", err
322 }
323
324 if cluster.APLEnabled {
325 return fmt.Sprintf("https://auth.lke%d.akamai-apl.net/ready", cluster.ID), nil
326 }
327
328 return "", nil
329 }
330