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