commands/operator-sdk: Add CLI support for Ansible Operator#486
Conversation
shawn-hurley
left a comment
There was a problem hiding this comment.
Some comments even though this is WIP
| } | ||
|
|
||
| func determineOperatorType() string { | ||
| if _, err := os.Stat(watchesYaml); err == nil { |
There was a problem hiding this comment.
@dymurray I would prefer this to be if there is a go file in the cmd dir rather than if a watches file exists.
The reason is, if there is a go the main file, we should build that, if there is not then we assume ansible. This will be less error-prone and should handle other use cases like building a go operator but using some of the ansible operators.
There was a problem hiding this comment.
On the other hand, we probably shouldn't assume that the lack of go source means ansible. Other types, like perhaps helm, may not have go source either. It could be best to positively identify one or the other, and let the default be "error; no operator type detected".
There was a problem hiding this comment.
Considering all that happens now, is a build of the dockerfile, that seems like the reasonable default IMO. If we add a third type we can deal with the differences then IMO.
There was a problem hiding this comment.
Need to change this so that we first check for cmd/<name>/main.go and if we find it we build just like we expect for a normal golang operator except with the Ansible Operator Dockerfile.
| newCmd.MarkFlagRequired("kind") | ||
| newCmd.Flags().StringVar(&operatorType, "type", "go", "Type of operator to initialize (e.g \"ansible\")") | ||
| newCmd.Flags().BoolVar(&skipGit, "skip-git-init", false, "Do not init the directory as a git repository") | ||
| newCmd.Flags().BoolVar(&generatePlaybook, "generate-playbook", false, "Generate a playbook skeleton in watches.yaml for Ansible Operator") |
There was a problem hiding this comment.
Mention that this is only used for type ansible.
| } | ||
| pullDep() | ||
| generate.K8sCodegen(projectName) | ||
| if operatorType == "go" { |
There was a problem hiding this comment.
This is the second time we are comparing this value, might as well make it a constant?
6df8bfe to
d240c1e
Compare
shawn-hurley
left a comment
There was a problem hiding this comment.
@dymurray I am wondering if we may want to create multiple generator(common/ansible/go) types with a Generator interface. This way we do not have switch statements in multiple places but rather a type that encapsulates generating that type.
WDYT?
| crdCmd := &cobra.Command{ | ||
| Use: "crd", | ||
| Short: "Generates a custom resource definition", | ||
| Long: `generates a custom resource definition (CRD) file for the . |
There was a problem hiding this comment.
Are we missing the end of this?
| Version: version(apiVersion), | ||
| } | ||
| crdFilePath := filepath.Join(deployDir, strings.ToLower(kind) + "_crd.yaml") | ||
| return renderWriteFile(crdFilePath, crdFilePath, crdYamlTmpl, crdTd) |
There was a problem hiding this comment.
I think this should create a cr.yaml for the new CRD as well, IMO.
There was a problem hiding this comment.
ok. i will update to add cr.yaml as well
| return renderWriteFile(crdFilePath, crdFilePath, crdYamlTmpl, crdTd) | ||
| } | ||
|
|
||
| func renderDeployFiles(deployDir, projectName, apiVersion, kind, operatorType string) error { |
There was a problem hiding this comment.
this should use the RenderDeployCrdFile IMO
| fmt.Fprintln(os.Stdout, "Generating custom resource definition (CRD) file") | ||
|
|
||
| // Generate CRD file | ||
| if err := generator.RenderDeployCrdFile(apiVersion, kind); err != nil { |
There was a problem hiding this comment.
Is there a way to verify that we are in the project root when running this command? I am a little worried that we are not guarding against that, and could have some odd behavior for the user.
There was a problem hiding this comment.
agreed. I've made an update to check for the ./deploy sub-directory
|
@shawn-hurley That makes sense to me. Especially if operator-sdk is going to be expanded to encapsulate other types of operators. Some of these functions however I felt that it was useful to encapsulate everything in the same place. Rendering |
| newCmd.MarkFlagRequired("kind") | ||
| newCmd.Flags().StringVar(&operatorType, "type", "go", "Type of operator to initialize (e.g \"ansible\")") | ||
| newCmd.Flags().BoolVar(&skipGit, "skip-git-init", false, "Do not init the directory as a git repository") | ||
| newCmd.Flags().BoolVar(&generatePlaybook, "generate-playbook", false, "Generate a playbook skeleton in watches.yaml. (Only used for --type ansible)") |
There was a problem hiding this comment.
Should this say "and watches.yaml"? A playbook skeleton would be created separately on the filesystem, and then referenced from within watches.yaml. It may be confusing to say the skeleton of a playbook will be in watches.yaml.
There was a problem hiding this comment.
Good catch. Your wording is far more accurate.
There was a problem hiding this comment.
Actually... I'm going to remove and watches.yaml and just leave it at Generate a playbook skeleton since we always generate watches.yaml when --type ansible.
| return err | ||
| } | ||
| default: | ||
| return errors.New(fmt.Sprintf("unexpected operator type [%v]", g.operatorType)) |
|
@johnkim76 You might be best to answer Shawn's questions above |
41ce6d7 to
2df7785
Compare
@shawn-hurley Yes we'll definitely need a more general generator/scaffolder. Right now we're only coupling the templates and their inputs structs together and just generate each file individually i.e we don't use a generator, but we'll eventually have to add a more general layer to handle that for any kind of file(). With a more general generator/scaffolder we could just change the inputs (based on the CLI command and type of operator) and generate the necessary files. But we'll have to think that through a bit more and not in this PR I think. |
529f74a to
5286eb3
Compare
|
@shawn-hurley @hasbro17 In response to your comments, is there anything you'd like me to change about my implementation in the scaffolding logic? Or is this something that you'd like to address at a later time? |
|
I think @hasbro17 wants to deal with it later, so no changes. |
|
@dymurray when you get a chance could you please rebase? |
c371dcb to
310544f
Compare
|
lgtm after nits |
|
@hasbro17 was your review complete and does this now look good to you? |
|
@shawn-hurley Sorry I got busy with a couple of other reviews. I'll finish reviewing this today. |
| if err != nil { | ||
| cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to build: (%v)", string(o))) | ||
| // Don't need to buld go code if Ansible Operator | ||
| if buildCmd() { |
There was a problem hiding this comment.
Can you change the name to be more representative of the actual function?
Right now it's just checking if cmd/<project-name>/main.go exists to determine if it's an Ansible or Go type project.
So perhaps mainExists() or isGoProject().
| fmt.Fprintln(os.Stdout, "Generating custom resource definition (CRD) file") | ||
|
|
||
| // generate CRD file | ||
| wd, _ := os.Getwd() |
| Short: "Generates a custom resource definition (CRD) and the custom resource (CR) files", | ||
| Long: `The operator-sdk generate command will create a custom resource definition (CRD) and the custom resource (CR) files for the specified api-version and kind. | ||
|
|
||
| Generated CRD filename: <project-name>/deploy/<kind>_crd.yaml |
There was a problem hiding this comment.
@shawn-hurley Just wanted to point out that if you try to generate a second CRD with the same Kind but different APIVersion then that will overwrite the previous <kind>_crd.yaml. Not sure if that's a legitimate use case in an ansible type project but we account for multiple CRDs in the refactor branch by using the format deploy/crds/<group>_<version>_<kind>_crd.yaml
We'll soon add the changes from this PR into the refactor branch as well(to fit the style of the scaffold).
Right now we don't have a separate generate CRD command but I'm wondering if you wanted to make the CRD generation consistent with how we do it in the refactor branch.
There was a problem hiding this comment.
This makes sense to me... @johnkim76 any concerns around this?
There was a problem hiding this comment.
that sounds good. I'll make the update to the filename. thank you.
| // │ │ └── <kind> | ||
| // │ ├── watches.yaml | ||
| // │ ├── deploy | ||
| // │ │ ├── <kind>-CRD.yaml |
There was a problem hiding this comment.
Minor nit but unless I'm mistaken, operator-sdk new --type=ansible --api-version=<apiversion> --kind=<kind> will still generate:
// │ ├── deploy
// │ │ ├── crd.yaml
// │ │ ├── rbac.yaml
// │ │ ├── operator.yaml
// │ ├ └── cr.yaml
<kind>_crd.yaml and <kind>_cr.yaml are only generated by operator-sdk generate crd --kind --api-version.
See renderDeployFiles() below. Although that should still be fine I think.
There was a problem hiding this comment.
@johnkim76 is this intended? Would you prefer that we change the new output to have the same filenames?
There was a problem hiding this comment.
yes, I think we should change the new behavior to have the <g>_<v>_<k>_cr.yaml and <g>_<v>_<k>_crd.yaml names.
There was a problem hiding this comment.
@johnkim76 based on Shawn's comment below we are going to hold off on that for the refactoring.
| func (g *Generator) renderRole() error { | ||
| fmt.Printf("Rendering Ansible Galaxy role [%v/%v/%v]...\n", g.projectName, rolesDir, g.kind) | ||
| agcmd := exec.Command(filepath.Join(g.projectName, galaxyInitCmd)) | ||
| _, err := agcmd.CombinedOutput() |
There was a problem hiding this comment.
It might be worth logging or returning the CombinedOutput here as well if the command fails.
The galaxyInit script might run but exit with an error. In which case the stdout and stderr might be more useful to see.
The err returned will just only say that the command exited with exit code 1.
|
LGTM after nits. @shawn-hurley We don't have to address the changes to the |
|
Thanks a lot for the feedback @hasbro17. @johnkim76 I would like your thoughts on the |
|
@dymurray @johnkim76 I think that we can fix the filenames for the generation command now, and then deal with the new command in the refactor branch as @hasbro17 suggested. I think this will work better because we shouldn't be changing new for everyone unless it is on the refactor branch IMO and fixing the CRD generation is new and shouldn't have expectations around it already. Does this make sense to everyone? |
|
|
||
| // verifyCrdDeployPath checks if the path <project-name>/deploy sub-directory is exists, and that is rooted under $GOPATH | ||
| func verifyCrdDeployPath() { | ||
| // check if $GOPATH env exists |
There was a problem hiding this comment.
While re-looking at the code, I would like to change one more thing about the generation as well
I think an ansible operator new, should not have to have Gopath set up. I think this would force users to have that, and I think we should avoid this.
@johnkim76 I wonder if we should just check that the current working dir has a deploy directory instead?
There was a problem hiding this comment.
ok.. I'll remove the check for the Gopath
There was a problem hiding this comment.
Good catch Shawn. I agree we shouldn't depend on Go being configured.
…ator-framework#546) * commands,pkg/test: support single namespace mode for local test This commit brings support for running the tests in a single namespace when using `test local`, which was previously only used by `test cluster` (where it was a requirement to properly function) * doc: update docs with new test local --namespace flag * pkg/test/resource_creator.go: check namespace env value * pkg/test: change handling of TestNamespaceEnv
…or-framework#548) PR operator-framework#525 changed the way that dep worked to fix dependency issues when doing e2e tests on travis. The PR breaks e2e testing on local machines though, as the tests will just use the master branch instead of a local branch. This commit symlinks the local sdk into vendor on non-travis tests. The tests will still fail on local machines if there is a dependency change, but we are unable to fix this on local machines unless `dep` adds local repo support.
|
@shawn-hurley Sounds good to me. |
operator-sdk new --type ansibleoperator-sdk buildsupport. Autodetect type of operator by looking forwatches.yamloperator-sdk generatesupport.[ ]Going to break this out to a separate PRoperator-sdk up localsupport.