Skip to content

Instantly share code, notes, and snippets.

@detiber
Last active July 24, 2018 19:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save detiber/956994cd466e7d3571646590e480737e to your computer and use it in GitHub Desktop.
Save detiber/956994cd466e7d3571646590e480737e to your computer and use it in GitHub Desktop.
Encoding/Decoding Provider Status
package machine
import (
"fmt"
"github.com/aws/aws-sdk-go/service/elbv2/elbv2iface"
"github.com/aws/aws-sdk-go/service/iam/iamiface"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/golang/glog"
clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
client "sigs.k8s.io/cluster-api/pkg/client/clientset_generated/clientset/typed/cluster/v1alpha1"
clusterstates "github.com/heptio/cluster-api-aws/internal/actuators"
awsclient "github.com/heptio/cluster-api-aws/internal/clients/aws"
clusterclient "github.com/heptio/cluster-api-aws/internal/clients/clusterapi"
providerconfigv1 "github.com/heptio/cluster-api-aws/providerconfig/v1alpha1"
)
// Actuator is responsible for performing machine reconciliation
type Actuator struct {
clusterClient clusterclient.ClientInterface
awsClient awsclient.ClientInterface
providerCodec *providerconfigv1.AWSProviderConfigCodec
providerConfig *providerconfigv1.AWSMachineProviderConfig
providerStatus *providerconfigv1.AWSMachineProviderStatus
clusterProviderConfig *providerconfigv1.AWSClusterProviderConfig
clusterProviderStatus *providerconfigv1.AWSClusterProviderStatus
region string
}
// ActuatorParams holds parameter information for Actuator
type ActuatorParams struct {
ClusterClient client.ClusterInterface
MachineClient client.MachineInterface
Ec2Client ec2iface.EC2API
Elbv2Client elbv2iface.ELBV2API
IAMClient iamiface.IAMAPI
}
// NewActuator creates a new Actuator
func NewActuator(params ActuatorParams) (*Actuator, error) {
// TODO: pull this from ProviderConfig
region := "us-east-1"
awsClient, err := awsclient.NewClient(
awsclient.ClientParams{
Ec2Client: params.Ec2Client,
Elbv2Client: params.Elbv2Client,
IAMClient: params.IAMClient,
Region: region,
},
)
if err != nil {
return nil, fmt.Errorf("Failed to create aws client: %v", err)
}
clusterClient, err := clusterclient.NewClient(
clusterclient.ClientParams{
ClusterClient: params.ClusterClient,
MachineClient: params.MachineClient,
},
)
if err != nil {
return nil, fmt.Errorf("Failed to create cluster-api client: %v", err)
}
codec, err := providerconfigv1.NewCodec()
if err != nil {
return nil, err
}
return &Actuator{
clusterClient: clusterClient,
awsClient: awsClient,
region: region,
providerCodec: codec,
}, nil
}
// Create creates a machine and is invoked by the Machine Controller
func (a *Actuator) Create(cluster *clusterv1.Cluster, machine *clusterv1.Machine) error {
glog.Infof("Creating machine %v for cluster %v.", machine.Name, cluster.Name)
// Set providerConfigs and providerStatuses
err := a.loadProviderConfigs(cluster, machine)
if err != nil {
return fmt.Errorf("error decoding ProviderConfig: %v", err)
}
err = a.loadProviderStatuses(cluster, machine)
if err != nil {
return fmt.Errorf("error decoding ProviderStatus: %v", err)
}
if a.clusterProviderStatus.State != clusterstates.Ready {
return fmt.Errorf("waiting for cluster to be ready")
}
// Ensure we update the Machine ProviderStatus
defer a.updateProviderStatus(machine)
...
}
...
func (a *Actuator) loadProviderConfigs(cluster *clusterv1.Cluster, machine *clusterv1.Machine) error {
a.providerConfig = &providerconfigv1.AWSMachineProviderConfig{}
err := a.providerCodec.DecodeFromProviderConfig(machine.Spec.ProviderConfig, a.providerConfig)
if err != nil {
return err
}
a.clusterProviderConfig = &providerconfigv1.AWSClusterProviderConfig{}
return a.providerCodec.DecodeFromProviderConfig(cluster.Spec.ProviderConfig, a.clusterProviderConfig)
}
func (a *Actuator) loadProviderStatuses(cluster *clusterv1.Cluster, machine *clusterv1.Machine) error {
a.providerStatus = &providerconfigv1.AWSMachineProviderStatus{}
err := a.providerCodec.DecodeProviderStatus(machine.Status.ProviderStatus, a.providerStatus)
if err != nil {
return err
}
a.clusterProviderStatus = &providerconfigv1.AWSClusterProviderStatus{}
return a.providerCodec.DecodeProviderStatus(cluster.Status.ProviderStatus, a.clusterProviderStatus)
}
func (a *Actuator) updateProviderStatus(machine *clusterv1.Machine) {
if a.providerStatus != nil {
encodedProviderStatus, err := a.providerCodec.EncodeProviderStatus(a.providerStatus)
if err != nil {
glog.Error("error encoding ProviderStatus")
}
if encodedProviderStatus != nil {
machine.Status.ProviderStatus = encodedProviderStatus
_, err = a.clusterClient.UpdateMachineProviderStatus(machine)
if err != nil {
glog.Error("error updating machine ProviderStatus: %v", err)
}
}
}
}
...
func (codec *AWSProviderConfigCodec) DecodeFromProviderConfig(providerConfig clusterv1.ProviderConfig, out runtime.Object) error {
if providerConfig.Value != nil {
_, _, err := codec.decoder.Decode(providerConfig.Value.Raw, nil, out)
if err != nil {
return fmt.Errorf("decoding failure: %v", err)
}
}
return nil
}
func (codec *AWSProviderConfigCodec) EncodeToProviderConfig(in runtime.Object) (*clusterv1.ProviderConfig, error) {
var buf bytes.Buffer
if err := codec.encoder.Encode(in, &buf); err != nil {
return nil, fmt.Errorf("encoding failed: %v", err)
}
return &clusterv1.ProviderConfig{
Value: &runtime.RawExtension{Raw: buf.Bytes()},
}, nil
}
func (codec *AWSProviderConfigCodec) EncodeProviderStatus(in runtime.Object) (*runtime.RawExtension, error) {
var buf bytes.Buffer
if err := codec.encoder.Encode(in, &buf); err != nil {
return nil, fmt.Errorf("encoding failed: %v", err)
}
return &runtime.RawExtension{Raw: buf.Bytes()}, nil
}
func (codec *AWSProviderConfigCodec) DecodeProviderStatus(providerStatus *runtime.RawExtension, out runtime.Object) error {
if providerStatus != nil {
_, _, err := codec.decoder.Decode(providerStatus.Raw, nil, out)
if err != nil {
return fmt.Errorf("decoding failure: %v", err)
}
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment