Go interface design for a cluster provisioner application
$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!
object-oriented design-patterns go
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$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!
object-oriented design-patterns go
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
add a comment |
$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!
object-oriented design-patterns go
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
$endgroup$
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!
object-oriented design-patterns go
object-oriented design-patterns go
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 3 hours ago
ragasragas
1
1
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
ragas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
ragas is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211502%2fgo-interface-design-for-a-cluster-provisioner-application%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
ragas is a new contributor. Be nice, and check out our Code of Conduct.
ragas is a new contributor. Be nice, and check out our Code of Conduct.
ragas is a new contributor. Be nice, and check out our Code of Conduct.
ragas is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211502%2fgo-interface-design-for-a-cluster-provisioner-application%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown