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 acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.