0
\$\begingroup\$

I'm fairly new to Go and working on an application to create VMs in a some cloud provider. I'm trying to design interfaces and I'd love some reviews.

The application creates a cluster (group of VMs with some software installed). The cluster has two roles: master and worker. And in each role, you can have node groups (master can have only one node group and worker role can have N node groups). So a role provisions N groups and a group provisions M nodes, updating status objects after each step. Here's what I've come up with so far (I've removed method parameters to make it easy to read):

// Initialize is used to initialize objects during a cluster creation. Use this
// at the given level (Role, Group or Node) to initialize things like status
// objects specific to that level.
type Initializer interface {
    // Initialize inits objects in a Cluster type.
    Initialize() error
}

// StatusUpdater is used to update status of Group or Node at a given level.
type StatusUpdater interface {
    // UpdateStatus updates the ClusterStatus object.
    UpdateStatus() error
}

// Deleter deletes clusters, node groups and nodes.
type Deleter interface {
    // RunPreDelete is used to run things before deletion of resources.
    RunPreDelete() error
    // Delete deletes a Role, Group or Node interface.
    Delete()
    // RunPostDelete is used to run things after deletion of resources.
    RunPostDelete() error
}

// Upgrade upgrades clusters and node groups.
type Upgrader interface {
    // Upgradeable is used to determine if the cluster is ready for an upgrade.
    Upgradeable() bool
    // PrepareForUpgrade is used to prepare a Group for upgrade, like setting status to upgrading
    PrepareForUpgrade() bool
    UpgradeStrategy
}

// UpgradeStategy defines strategies for upgrade. Default strategy is delete a node and create an
// "upgraded" node. The default strategy reduces workload capacity during upgrade. Additive strategy
// creates a new node and when it is ready, registers new node with the cluster and removes the old
// node. This gives additional workload capacity during upgrade. 
type UpgradeStrategy interface {
    // Upgrade upgrades a cluster or a group.
    Upgrade() error
}

// Ensurer ensures a resource is created and present.
type Ensurer interface {
    // Ensure ensures a resource.
    Ensure() error
}

// Provisioner provisions a Role (master or worker) in the cluster. This is the top level provisioner for
// a K8S cluster.
type Provisioner interface {
    Initializer
    // Role returns role name of the provisioner.
    Role() string
    // ProvisionRole provisions a K8S cluster role.
    ProvisionRole() error
    StatusUpdater
    Deleter
}

// GroupProvisoner provisions a Group (master group and one or more worker groups).
type GroupProvisoner interface {
    Initializer
    // ProvisionGroup provisions a Group.
    ProvisionGroup() error
    StatusUpdater
    Deleter
}

// NodeProvisioner provisions an individual node using the cloud provider APIs.
type NodeProvisioner interface {
    Initializer
    Ensurer
    StatusUpdater
    Deleter
}

// Node implements NodeProvisioner interface
type Node struct{}

// Group implements GroupProvisioner interface
type Group struct {
    NodeProvisioner NodeProvisioner
}

// Master implements Provisioner
type Master struct {
    Role            string
    GroupProvisoner GroupProvisoner
    Upgrader        Upgrader
    StatusUpdater   StatusUpdater
}

func NewMaster() Provisioner {
    // Inject dependencies and return a &Master
}

Does this look like a good design? Is it idiomatic Go? Any suggestions are greatly appreciated!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.