-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
commands/operator-sdk: Add CLI support for Ansible Operator #486
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments even though this is WIP
commands/operator-sdk/cmd/build.go
Outdated
if err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to output build image %v: (%v)", image, string(o))) | ||
} | ||
fmt.Fprintln(os.Stdout, string(o)) | ||
} | ||
|
||
func determineOperatorType() string { | ||
if _, err := os.Stat(watchesYaml); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
commands/operator-sdk/cmd/new.go
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mention that this is only used for type ansible.
commands/operator-sdk/cmd/new.go
Outdated
err := g.Render() | ||
if err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to create project %v: %v", projectName, err)) | ||
} | ||
pullDep() | ||
generate.K8sCodegen(projectName) | ||
if operatorType == "go" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the second time we are comparing this value, might as well make it a constant?
6df8bfe
to
d240c1e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we missing the end of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops... yes.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should create a cr.yaml for the new CRD as well, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
commands/operator-sdk/cmd/new.go
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Your wording is far more accurate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
.
pkg/generator/generator.go
Outdated
return err | ||
} | ||
default: | ||
return errors.New(fmt.Sprintf("unexpected operator type [%v]", g.operatorType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out fmt.Errorf()
@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. |
commands/operator-sdk/cmd/build.go
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check return error.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense to me... @johnkim76 any concerns around this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@johnkim76 based on Shawn's comment below we are going to hold off on that for the refactoring.
pkg/generator/generator.go
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok.. I'll remove the check for the Gopath
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 ansible
operator-sdk build
support. Autodetect type of operator by looking forwatches.yaml
operator-sdk generate
support.[ ]Going to break this out to a separate PRoperator-sdk up local
support.