-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Changes from 8 commits
3f39fb9
c227034
e99de5e
7cadcea
1df6e55
1f68aed
b10bc85
15fe320
6ba4d7e
249d7b1
02f1155
20c4791
4c72ad8
096ae3a
a47f90f
1962e6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ import ( | |
"log" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
|
||
"github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/cmdutil" | ||
cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error" | ||
|
@@ -135,29 +136,33 @@ func renderTestManifest(image string) { | |
const ( | ||
build = "./tmp/build/build.sh" | ||
configYaml = "./config/config.yaml" | ||
mainGo = "./cmd/%s/main.go" | ||
) | ||
|
||
func buildFunc(cmd *cobra.Command, args []string) { | ||
if len(args) != 1 { | ||
cmdError.ExitWithError(cmdError.ExitBadArgs, fmt.Errorf("build command needs exactly 1 argument")) | ||
} | ||
|
||
bcmd := exec.Command(build) | ||
bcmd.Env = append(os.Environ(), fmt.Sprintf("TEST_LOCATION=%v", testLocationBuild)) | ||
bcmd.Env = append(bcmd.Env, fmt.Sprintf("ENABLE_TESTS=%v", enableTests)) | ||
o, err := bcmd.CombinedOutput() | ||
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() { | ||
bcmd := exec.Command(build) | ||
bcmd.Env = append(os.Environ(), fmt.Sprintf("TEST_LOCATION=%v", testLocationBuild)) | ||
bcmd.Env = append(bcmd.Env, fmt.Sprintf("ENABLE_TESTS=%v", enableTests)) | ||
o, err := bcmd.CombinedOutput() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As @AlexNPavel mentioned: You need to pass the envs from L146-147 to the build command. bcmd.Env = append(os.Environ(), fmt.Sprintf("TEST_LOCATION=%v", testLocationBuild))
bcmd.Env = append(bcmd.Env, fmt.Sprintf("ENABLE_TESTS=%v", enableTests)) We made this change in #469 Although we're planning to remove the build script altogether in #541 so you might need to rebase again if that gets done first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks a lot for updating that @johnkim76. Appreciate the heads up on #541 as well |
||
if err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to build: (%v)", string(o))) | ||
} | ||
fmt.Fprintln(os.Stdout, string(o)) | ||
} | ||
fmt.Fprintln(os.Stdout, string(o)) | ||
|
||
image := args[0] | ||
baseImageName := image | ||
if enableTests { | ||
baseImageName += "-intermediate" | ||
} | ||
dbcmd := exec.Command("docker", "build", ".", "-f", "tmp/build/Dockerfile", "-t", baseImageName) | ||
o, err = dbcmd.CombinedOutput() | ||
o, err := dbcmd.CombinedOutput() | ||
if err != nil { | ||
if enableTests { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to build intermediate image for %s image: (%s)", image, string(o))) | ||
|
@@ -178,3 +183,16 @@ func buildFunc(cmd *cobra.Command, args []string) { | |
renderTestManifest(image) | ||
} | ||
} | ||
|
||
func buildCmd() bool { | ||
dir, err := os.Getwd() | ||
if err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to get current working dir: %v", err)) | ||
} | ||
dirSplit := strings.Split(dir, "/") | ||
projectName := dirSplit[len(dirSplit)-1] | ||
if _, err = os.Stat(fmt.Sprintf(mainGo, projectName)); err == nil { | ||
return true | ||
} | ||
return false | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright 2018 The Operator-SDK Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package generate | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error" | ||
"github.com/operator-framework/operator-sdk/pkg/generator" | ||
|
||
"github.com/spf13/cobra" | ||
dymurray marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
var ( | ||
apiVersion string | ||
kind string | ||
) | ||
|
||
const ( | ||
goDir = "GOPATH" | ||
deployCrdDir = "deploy" | ||
) | ||
|
||
func NewGenerateCrdCmd() *cobra.Command { | ||
crdCmd := &cobra.Command{ | ||
Use: "crd", | ||
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 commentThe 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 We'll soon add the changes from this PR into the refactor branch as well(to fit the style of the scaffold). There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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. |
||
Generated CR filename: <project-name>/deploy/<kind>_cr.yaml | ||
|
||
<project-name>/deploy path must already exist | ||
--api-version and --kind are required flags to generate the new operator application. | ||
`, | ||
Run: crdFunc, | ||
} | ||
crdCmd.Flags().StringVar(&apiVersion, "api-version", "", "Kubernetes apiVersion and has a format of $GROUP_NAME/$VERSION (e.g app.example.com/v1alpha1)") | ||
crdCmd.MarkFlagRequired("api-version") | ||
crdCmd.Flags().StringVar(&kind, "kind", "", "Kubernetes CustomResourceDefintion kind. (e.g AppService)") | ||
crdCmd.MarkFlagRequired("kind") | ||
return crdCmd | ||
} | ||
|
||
func crdFunc(cmd *cobra.Command, args []string) { | ||
if len(args) != 0 { | ||
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("crd command doesn't accept any arguments.")) | ||
} | ||
verifyCrdFlags() | ||
verifyCrdDeployPath() | ||
|
||
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 commentThe reason will be displayed to describe this comment to others. Learn more. Check return error. |
||
if err := generator.RenderDeployCrdFiles(filepath.Join(wd, deployCrdDir), apiVersion, kind); err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to generate CRD and CR files: (%v)", err)) | ||
} | ||
} | ||
|
||
func verifyCrdFlags() { | ||
if len(apiVersion) == 0 { | ||
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--api-version must not have empty value")) | ||
} | ||
if len(kind) == 0 { | ||
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--kind must not have empty value")) | ||
} | ||
kindFirstLetter := string(kind[0]) | ||
if kindFirstLetter != strings.ToUpper(kindFirstLetter) { | ||
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--kind must start with an uppercase letter")) | ||
} | ||
if strings.Count(apiVersion, "/") != 1 { | ||
cmdError.ExitWithError(cmdError.ExitBadArgs, fmt.Errorf("api-version has wrong format (%v); format must be $GROUP_NAME/$VERSION (e.g app.example.com/v1alpha1)", apiVersion)) | ||
} | ||
} | ||
|
||
// 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 commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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. |
||
gp := os.Getenv(goDir) | ||
if len(gp) == 0 { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("$GOPATH env not set")) | ||
} | ||
wd, err := os.Getwd() | ||
if err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to determine the full path of the current directory: %v", err)) | ||
} | ||
// check if this project's repository path is rooted under $GOPATH | ||
if !strings.HasPrefix(wd, gp) { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("project's repository path (%v) is not rooted under GOPATH (%v)", wd, gp)) | ||
} | ||
// check if the deploy sub-directory exist | ||
_, err = os.Stat(filepath.Join(wd, deployCrdDir)) | ||
if err != nil { | ||
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("the path (./%v) does not exist. run this command in your project directory", deployCrdDir)) | ||
} | ||
} |
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()
orisGoProject()
.