Skip to content

Commit

Permalink
chore: stage provider-kops progress
Browse files Browse the repository at this point in the history
  • Loading branch information
austinbrown-okta committed Aug 22, 2024
1 parent 0812cb5 commit 07291ac
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 29 deletions.
86 changes: 59 additions & 27 deletions apis/v1alpha1/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type ClusterParameters struct {

RollingUpdateOpts RollingUpdateOptsSpec `json:"rollingUpdateOpts,omitempty"`

Keypairs []KeypairSpec `json:"keypairs,omitempty"`

Secrets []SecretSpec `json:"secrets,omitempty"`

// Cluster is the spec provided for the kops api ClusterSpec; ref:
Expand All @@ -45,17 +47,28 @@ type ClusterParameters struct {
}

type RollingUpdateOptsSpec struct {
BastionInterval *string `json:"bastionInterval,omitempty"`
CloudOnly *bool `json:"cloudOnly,omitempty"`
// +kubebuilder:default="15s"
BastionInterval *string `json:"bastionInterval,omitempty"`
// +kubebuilder:default=false
CloudOnly *bool `json:"cloudOnly,omitempty"`
// +kubebuilder:default="15s"
ControlPlaneInterval *string `json:"controlPlaneInterval,omitempty"`
DrainTimeout *string `json:"drainTimeout,omitempty"`
FailOnDrainError *bool `json:"failOnDrainError,omitempty"`
FailOnValidateError *bool `json:"failOnValidateError,omitempty"`
Force *bool `json:"force,omitempty"`
NodeInterval *string `json:"nodeInterval,omitempty"`
PostDrainDelay *string `json:"postDrainDelay,omitempty"`
ValidateCount *int32 `json:"validateCount,omitempty"`
ValidationTimeout *string `json:"validationTimeout,omitempty"`
// +kubebuilder:default="15m0s"
DrainTimeout *string `json:"drainTimeout,omitempty"`
// +kubebuilder:default=true
FailOnDrainError *bool `json:"failOnDrainError,omitempty"`
// +kubebuilder:default=true
FailOnValidateError *bool `json:"failOnValidateError,omitempty"`
// +kubebuilder:default=false
Force *bool `json:"force,omitempty"`
// +kubebuilder:default="15s"
NodeInterval *string `json:"nodeInterval,omitempty"`
// +kubebuilder:default="15s"
PostDrainDelay *string `json:"postDrainDelay,omitempty"`
// +kubebuilder:default=2
ValidateCount *int32 `json:"validateCount,omitempty"`
// +kubebuilder:default="15m0s"
ValidationTimeout *string `json:"validationTimeout,omitempty"`
}

// *****
Expand Down Expand Up @@ -160,10 +173,12 @@ const (
)

type FileAssetSpec struct {
Content string `yaml:"content" json:"content"`
Name string `yaml:"name" json:"name"`
Path string `yaml:"path" json:"path"`
Roles []ClusterFileAssetRole `yaml:"roles" json:"roles"`
Content string `yaml:"content" json:"content"`
// +kubebuilder:default="0440"
Mode string `yaml:"mode" json:"mode"`
Name string `yaml:"name" json:"name"`
Path string `yaml:"path" json:"path"`
Roles []ClusterFileAssetRole `yaml:"roles" json:"roles"`
}

// +kubebuilder:validation:Enum=Master;Node
Expand Down Expand Up @@ -210,19 +225,21 @@ type IAMSpec struct {
}

type KubeAPIServerSpec struct {
APIAudiences []string `yaml:"apiAudiences,omitempty" json:"apiAudiences,omitempty"`
DisableBasicAuth bool `yaml:"disableBasicAuth" json:"disableBasicAuth"`
OidcClientID string `yaml:"oidcClientID" json:"oidcClientID"`
OidcGroupsClaim string `yaml:"oidcGroupsClaim" json:"oidcGroupsClaim"`
OidcIssuerURL string `yaml:"oidcIssuerURL" json:"oidcIssuerURL"`
OidcUsernameClaim string `yaml:"oidcUsernameClaim" json:"oidcUsernameClaim"`
AuditLogMaxAge int `yaml:"auditLogMaxAge" json:"auditLogMaxAge"`
AuditLogMaxBackups int `yaml:"auditLogMaxBackups" json:"auditLogMaxBackups"`
AuditLogMaxSize int `yaml:"auditLogMaxSize" json:"auditLogMaxSize"`
AuditLogPath string `yaml:"auditLogPath" json:"auditLogPath"`
AuditPolicyFile string `yaml:"auditPolicyFile" json:"auditPolicyFile"`
AuditWebhookBatchMaxWait string `yaml:"auditWebhookBatchMaxWait" json:"auditWebhookBatchMaxWait"`
AuditWebhookConfigFile string `yaml:"auditWebhookConfigFile" json:"auditWebhookConfigFile"`
APIAudiences []string `yaml:"apiAudiences,omitempty" json:"apiAudiences,omitempty"`
// +kubebuilder:default=/srv/kubernetes/ca.crt
ClientCAFile string `yaml:"clientCAFile" json:"clientCAFile"`
DisableBasicAuth bool `yaml:"disableBasicAuth" json:"disableBasicAuth"`
OidcClientID string `yaml:"oidcClientID" json:"oidcClientID"`
OidcGroupsClaim string `yaml:"oidcGroupsClaim" json:"oidcGroupsClaim"`
OidcIssuerURL string `yaml:"oidcIssuerURL" json:"oidcIssuerURL"`
OidcUsernameClaim string `yaml:"oidcUsernameClaim" json:"oidcUsernameClaim"`
AuditLogMaxAge int `yaml:"auditLogMaxAge" json:"auditLogMaxAge"`
AuditLogMaxBackups int `yaml:"auditLogMaxBackups" json:"auditLogMaxBackups"`
AuditLogMaxSize int `yaml:"auditLogMaxSize" json:"auditLogMaxSize"`
AuditLogPath string `yaml:"auditLogPath" json:"auditLogPath"`
AuditPolicyFile string `yaml:"auditPolicyFile" json:"auditPolicyFile"`
AuditWebhookBatchMaxWait string `yaml:"auditWebhookBatchMaxWait" json:"auditWebhookBatchMaxWait"`
AuditWebhookConfigFile string `yaml:"auditWebhookConfigFile" json:"auditWebhookConfigFile"`
}

type KubeletConfigSpec struct {
Expand Down Expand Up @@ -321,6 +338,21 @@ const (
// ***** END KopsClusterSpec and related *****
// *****

// *****
// ***** BEGIN KeypairSpec and related *****
// *****

type KeypairSpec struct {
Keypair string `yaml:"keypair" json:"keypair"`
Cert *string `yaml:"cert,omitempty" json:"cert,omitempty"`
Key *SecretSpec `yaml:"key,omitempty" json:"key,omitempty"`
Primary bool `yaml:"primary" json:"primary"`
}

// *****
// ***** END KeypairSpec and related *****
// *****

// *****
// ***** BEGIN SecretSpec and related *****
// *****
Expand Down
32 changes: 32 additions & 0 deletions apis/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion examples/cluster/overlays/simple/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ kind: Kustomization
namePrefix: simple-

resources:
- ./../../base
- ./../../base-simple

configurations:
- kustomizeconfig/clusterType.yaml
Expand Down
31 changes: 31 additions & 0 deletions internal/controller/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,33 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
log.Info(fmt.Sprintf("Post create update error: %s; %+v", err.Error(), err))
}

// TODO(ab): we need to provide lifecycle management for keypairs, rather
// than only providing bootstrap creation
for _, kp := range cr.Spec.ForProvider.Keypairs {
privateKeyData := []byte{}
if kp.Key != nil {
privateKeySource, err := resource.CommonCredentialExtractor(bgCtx, kp.Key.Value.Source, c.kube, kp.Key.Value.CommonCredentialSelectors)
privateKeyData = append(privateKeyData, privateKeySource...)
if err != nil {
log.Info(fmt.Sprintf("Post create keypair error: %s; %+v", err.Error(), err))
}
}
if err := c.service.createKeypair(bgCtx, cr, &kp, privateKeyData); err != nil {
log.Info(fmt.Sprintf("Post create keypair error: %s; %+v", err.Error(), err))
}
}
if len(cr.Spec.ForProvider.Keypairs) > 0 {
if err := c.service.updateCluster(bgCtx, cr); err != nil {
log.Info(fmt.Sprintf("POST CREATE UPDATE ERROR: %s; %+v", err.Error(), err))
}
// force cloudonly roll for initial cluster creation when keypairs are introduced
truePtr := bool(true)
cr.Spec.ForProvider.RollingUpdateOpts.CloudOnly = &truePtr
if err := c.service.rollingUpdateCluster(bgCtx, cr); err != nil {
log.Info(fmt.Sprintf("POST CREATE ROLLING UPDATE ERROR: %s; %+v", err.Error(), err))
}
}

if err := c.annotateCluster(bgCtx, cr, map[string]string{providerKopsCreateComplete: ""}); err != nil {
log.Info(fmt.Sprintf("WARNING: %s", err.Error()))
}
Expand Down Expand Up @@ -395,6 +422,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
log.Info(fmt.Sprintf("UPDATE ERROR: %s; %+v", err.Error(), err))
}

if err := c.service.rollingUpdateCluster(ctx, cr); err != nil {
log.Info(fmt.Sprintf("ROLLING UPDATE ERROR: %s; %+v", err.Error(), err))
}

if err := c.unlockCluster(bgCtx, cr, []string{providerKopsUpdateLocked}); err != nil {
log.Info(fmt.Sprintf("WARNING: %s; %+v", err.Error(), err))
}
Expand Down
54 changes: 53 additions & 1 deletion internal/controller/cluster/kops_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"

Expand Down Expand Up @@ -117,6 +118,57 @@ func (k *kopsClient) createCluster(_ context.Context, cr *v1alpha1.Cluster) erro
return nil
}

func (k *kopsClient) createKeypair(_ context.Context, cr *v1alpha1.Cluster, kp *v1alpha1.KeypairSpec, privateKeyData []byte) error {
args := []string{}
if kp.Primary {
args = append(args, "--primary=true")
}
if kp.Cert != nil {
f, err := os.CreateTemp(tmpDir, "*.crt")
if err != nil {
return err
}
_, err = f.Write([]byte(*kp.Cert))

Check failure on line 131 in internal/controller/cluster/kops_helpers.go

View workflow job for this annotation

GitHub Actions / lint

preferStringWriter: f.WriteString(*kp.Cert) should be preferred to the f.Write([]byte(*kp.Cert)) (gocritic)
if err != nil {
return err
}
args = append(args, fmt.Sprintf("--cert=%s", f.Name()))
defer os.Remove(f.Name())

Check failure on line 136 in internal/controller/cluster/kops_helpers.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `os.Remove` is not checked (errcheck)
}
if len(privateKeyData) > 0 {
f, err := os.CreateTemp(tmpDir, "*.pem")
if err != nil {
return err
}
_, err = f.Write(privateKeyData)
if err != nil {
return err
}
args = append(args, fmt.Sprintf("--key=%s", f.Name()))
defer os.Remove(f.Name())

Check failure on line 148 in internal/controller/cluster/kops_helpers.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `os.Remove` is not checked (errcheck)
}
//nolint:gosec
cmd := exec.Command(
"kops",
"create",
"keypair",
"-v5",
kp.Keypair,
fmt.Sprintf("--name=%s", getClusterExternalName(cr)),
fmt.Sprintf("--state=%s", cr.Spec.ForProvider.State),
)
cmd.Args = append(cmd.Args, args...)
cmd.Env = append(cmd.Env, getKopsCliEnv(cr, k)...)

if output, err := cmd.CombinedOutput(); err != nil {
return errors.Wrap(err, string(output))
} else {
log.Debug(string(output))
}

return nil
}

func (k *kopsClient) authenticateToCluster(ctx context.Context, cr *v1alpha1.Cluster, extraArgs []string) error {

//nolint:gosec
Expand Down Expand Up @@ -369,7 +421,7 @@ func (k *kopsClient) updateCluster(ctx context.Context, cr *v1alpha1.Cluster) er
log.Debug(fmt.Sprintf("Applied Update:%s", string(output)))
}

return k.rollingUpdateCluster(ctx, cr)
return nil
}

func (k *kopsClient) rollingUpdateCluster(ctx context.Context, cr *v1alpha1.Cluster) error {
Expand Down
2 changes: 2 additions & 0 deletions internal/controller/cluster/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const (
fileSuffixCreate = "create"
fileSuffixObserve = "observe"
fileSuffixUpdate = "update"

tmpDir = "/tmp"
)

type kopsClient struct {
Expand Down
Loading

0 comments on commit 07291ac

Please sign in to comment.