Skip to content
This repository was archived by the owner on Feb 5, 2020. It is now read-only.

Refactor workflow#3197

Closed
enxebre wants to merge 1 commit intocoreos:masterfrom
enxebre:refactor
Closed

Refactor workflow#3197
enxebre wants to merge 1 commit intocoreos:masterfrom
enxebre:refactor

Conversation

@enxebre
Copy link
Contributor

@enxebre enxebre commented Apr 20, 2018

The workflow package with the metadata shared by reference across steps has given us high flexibility and ability for making changes and prototype very quickly. As product requirements get clearer and we introduce a second platform we should define clearer boundaries, stronger interfaces and refactor the package.
This proposes a refactor into a more object oriented and hermetic flavour, less prone to side effects. The main logic is in cluster.go

@coreosbot
Copy link

Can one of the admins verify this patch?

@enxebre enxebre changed the title Refactor Refactor workflow Apr 23, 2018

// GenerateKubeConfig returns, if successful, the cluster kubernetes config
func (c ConfigGenerator) GenerateKubeConfig(workspace string) error {
//configGenerator := configgenerator.New(c.config)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete these comments?

func (c Cluster) runDestroyStep(step string, extraArgs ...string) error {
if !hasStateFile(c.workspace, step) {
// there is no statefile, therefore nothing to destroy for this step
return nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it make sense to log a warning here? or is this an expected state?

}
return tfApply(c.workspace, step, templateDir, extraArgs...)

return nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra return

if err := c.runInstallStep(assetsStep); err != nil {
return err
}
if err := c.generateKubeConfig(); err != nil {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a FYI, I had to move this before the runInstallStep(assetsStep) as part of #3183.

@alexsomesan
Copy link
Contributor

Wearing the Ed hat, I'd have to ask which sprint / epic issue does this change tie into?

Copy link
Contributor

@alexsomesan alexsomesan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workspace concept this change introduces is quite foreign to the problem domain that the installer tries to solve - that is, installing Kubernetes (Tectonic / OpenShift) clusters.

Let's try to take a deeper look at it and see how it fits.

Let me pose the following question:

As a user of this tool, I want to install a Tectonic / OpenShift cluster. Previously I could install a cluster without having to supply a workspace as input.
How does supplying a workspace name as an input improve my experience in achieving the goal of installing a cluster?

On the other hand, as a user of this tool, how does not supplying a workspace as an input hinder me from achieving the goal of installing the cluster?

Let's try to answer these questions from the perspective of a user expecting a running cluster after using this tool.

// returns the directory containing templates for a given step. If platform is
// specified, it looks for a subdirectory with platform first, falling back if
// there are no platform-specific templates for that step
func findStepTemplates(stepName, platform string) (string, error) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One little thing: could you convert platform to lower case? Otherwise I'll have to update that in a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexsomesan
Copy link
Contributor

As a side note, I'd prefer that major changes like this be discussed briefly as proposals before actually putting any code down.
This is to minimize friction in incorporating the change and making sure it's in the right shape to get in.

}

// Install runs, if successful, the steps to install a cluster
func (c Cluster) Install() error {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot cleaner, nice.

@enxebre
Copy link
Contributor Author

enxebre commented Apr 23, 2018

hey @alexsomesan on the workspace questions, there's actually no new concept, it's just renaming clusterDir to workspace. In addition (but it's no necessary), I also added it as a flag so the user can use the same source config file to init different clusters

@squeed
Copy link

squeed commented Apr 23, 2018

As part of this, it might be nice to abstract Cluster behind an interface; that would help with multi-platform.

@enxebre
Copy link
Contributor Author

enxebre commented Apr 23, 2018

@squeed I thought about the interface but wanted to keep as simple as possible for now. Let's add the abstraction if needed with the introduction of the second platform. It also crossed my mind to have a infraImpl interface composing the cluster struct to implement the desired functionality. Once we have two will be easier to abstract more if required

@enxebre enxebre force-pushed the refactor branch 2 times, most recently from b425ddb to e95f68c Compare April 23, 2018 12:50
var c *workflow.Cluster
var err error

newCluster := func(clusterInstallDirFlag string) *workflow.Cluster {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we pull this function definition out of the main func? there is no need to do this inline.

var c *workflow.Cluster
var err error

newCluster := func(clusterInstallDirFlag string) *workflow.Cluster {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clusterInstallDirFlag is a funny name for this parameter. the function should not care if it is a flag or an argument or how the string was provided to the function. Could simply be named dir.

var err error

newCluster := func(clusterInstallDirFlag string) *workflow.Cluster {
l, err := log.ParseLevel(*logLevel)
Copy link
Contributor

@squat squat May 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creating a cluster should be separate from parsing the log level. In fact, this change introduces a new behavior where log levels are not parsed for the convert command since that command does not execute this newCluster func. I think parsing the log level should be done outside of this func.

func (c ConfigGenerator) GenerateClusterConfigMaps(workspace string) error {
clusterGeneratedPath := filepath.Join(workspace, generatedPath)
if err := os.MkdirAll(clusterGeneratedPath, os.ModeDir|0755); err != nil {
return fmt.Errorf("Failed to create cluster generated directory at %s", clusterGeneratedPath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We typically make errors lower-case so they can be wrapped.


kubePath := filepath.Join(workspace, kubeSystemPath)
if err := os.MkdirAll(kubePath, os.ModeDir|0755); err != nil {
return fmt.Errorf("Failed to create manifests directory at %s", kubePath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above


tectonicPath := filepath.Join(workspace, tectonicSystemPath)
if err := os.MkdirAll(tectonicPath, os.ModeDir|0755); err != nil {
return fmt.Errorf("Failed to create tectonic directory at %s", tectonicPath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

// InitWorkspace generates, if successful, a workspace folder with the config.yaml
func InitWorkspace(sourceConfigFilePath, workspaceName string) error {
if sourceConfigFilePath == "" {
errors.New("no cluster sourceConfigFilePath given for instantiating new cluster")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a return? currently this line evaluates the errors.New func but does nothing with the returned value

errors.New("no cluster sourceConfigFilePath given for instantiating new cluster")
}
if workspaceName == "" {
errors.New("no cluster sourceConfigFilePath given for instantiating new cluster")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

// It ensures cluster.config and the tfvars file are always up to date with config.yaml
func NewCluster(workspace string) (*Cluster, error) {
if workspace == "" {
errors.New("no workspace dir given for new cluster")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

@enxebre
Copy link
Contributor Author

enxebre commented May 9, 2018

@squat thanks for having a look. Let's close this for now as more internal discussions is needed about the approach before going deeper into the code. cc @alexsomesan

@enxebre enxebre closed this May 9, 2018
// want that to happen atomically with generateTerraformVariables
func readClusterConfig(workspace string) (*config.Cluster, error) {
if workspace == "" {
errors.New("no workspace dir given for reading config")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement does not do anything with the returned value from errors.New. Did you mean to return here?


func (c Cluster) runDestroyStep(step string, extraArgs ...string) error {
if !hasStateFile(c.workspace, step) {
log.Warningf("there is no statefile, therefore nothing to destroy for the step %s within %s", step, c.workspace)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log lines typically begin with a capital letter

yamlContent, err := yaml.Marshal(internalCfg)
internalFileContent := []byte("# Do not touch, auto-generated\n")
internalFileContent = append(internalFileContent, yamlContent...)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's typical to put the error check immediately after the error declaration

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants