Skip to content
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

Create YAML or JSON Clusterspec without creating the cluster #2954

Merged

Conversation

chrislovecnm
Copy link
Contributor

@chrislovecnm chrislovecnm commented Jul 15, 2017

Allowing a user to create a YAML or JSON cluster or instance group without creating the object. Some of the new methods will be used to fix the problems we are having with JSON output as well. Reading an array of JSON objects is not yet supported by kops create -f, but a single JSON object is supported.

This implements

kops create cluster --dry-run -oyaml

TODOs

  • init or create
  • update cobra docs
  • figure out what is going on with unit tests
  • figure out was issue(s) this closes

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jul 15, 2017
@chrislovecnm
Copy link
Contributor Author

/assign @andrewsykim @sethpollack @geojaz @justinsb

We only need one, unless you are working on getting more PR reviews under your belt :)

@k8s-ci-robot
Copy link
Contributor

@chrislovecnm: GitHub didn't allow me to assign the following users: sethpollack.

Note that only kubernetes members can be assigned.

In response to this:

/assign @andrewsykim @sethpollack @geojaz @justinsb

We only need one, unless you are working on getting more PR reviews under your belt :)

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@JustEra
Copy link

JustEra commented Jul 15, 2017

AsfFor me and said on slack :

init would make more sense as it define a state that it should not "run" or "create" the cluster yet but only define the structure.

create would imply to me that the command really create it and that the cluster is more than a struct definition in a yaml.

I think it would confuse more people to have it in the create or at least we have to say like a dry-create

Would vote for the init even if its an alias of create subfunction.

@chrislovecnm chrislovecnm force-pushed the create-yaml-or-json branch from b625dc5 to 504d9a4 Compare July 15, 2017 20:37
@chrislovecnm
Copy link
Contributor Author

In terms of naming this on slack, we had two that liked init and one for create. kops create -o yaml is much easier to code, since I am pretty much reusing create.

@chrislovecnm chrislovecnm force-pushed the create-yaml-or-json branch from 504d9a4 to a486d28 Compare July 15, 2017 20:41
switch targetName {
case cloudup.TargetYAML:

var clusters []*api.Cluster
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can I inline the creation of this var? Could not figure out the syntax ...

@chrislovecnm
Copy link
Contributor Author

Marking WIP, as I need to refactor a bit, and figure out if we want to have init or create.

@chrislovecnm chrislovecnm force-pushed the create-yaml-or-json branch from a486d28 to dd96bed Compare July 15, 2017 21:08
@justinsb
Copy link
Member

kubectl uses kubectl create cluster, and it uses --dryrun -oyaml for the functionality I think you're targeting about now.

--target is not really the same concept (it is the final model, rather than the input models), so I'm not sure they should be conflated.

Still not sure what we're going to do in kops server mode, where k8s doesn't really have a user-driven "apply changes" step (our kops update)

@chrislovecnm
Copy link
Contributor Author

chrislovecnm commented Jul 15, 2017

So kubectl does have a dry run, but is this a dry run? Dry run to me means, execute something that will do something, and test that it will do the correct actions, without doing anything. That is pretty much what helm dry run does, but you have to have a manifest first.

This is something that helm, kubectl, etc do not really have ...

Maybe init ... pondering

@justinsb
Copy link
Member

Let's hold off on non-critical UX changes until we are building the UX for kops-server; I don't want to paint ourselves into a corner.

@justinsb justinsb added this to the kops-server milestone Jul 16, 2017
@hubt
Copy link

hubt commented Jul 16, 2017

I like init. I agree with @chrislovecnm on dry run being different.

@chrislovecnm
Copy link
Contributor Author

@justinsb this is the PR that I meant to comment on. This appears to be orthogonal to the kops-server. This is a utility that anyone would use to create yaml files to interact with the server.

This is something that kubectl, helm, frankly any component in k8s, that I know of, does not have.

Please exaplain how this would impact the kops-server.

@k8s-github-robot k8s-github-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 1, 2017
@k8s-github-robot k8s-github-robot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 13, 2017
@justinsb justinsb modified the milestones: kops-server, backlog Sep 23, 2017
@chrislovecnm
Copy link
Contributor Author

@justinsb PTAL - this was asked for on office hours

@justinsb justinsb added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 4, 2017
@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Nov 4, 2017
@chrislovecnm chrislovecnm removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 4, 2017
}

var targetOptions = sets.NewString(cloudup.TargetDryRun, cloudup.TargetCloudformation, cloudup.TargetDirect, cloudup.TargetTerraform)
Copy link
Member

Choose a reason for hiding this comment

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

I don't think dryrun should be an explicit target here in the CLI.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

correct ... will remove

case OutputYaml:

var clusters []*api.Cluster
cluster.ObjectMeta.CreationTimestamp = v1.NewTime(time.Now())
Copy link
Member

Choose a reason for hiding this comment

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

It looks like kubectl create secret generic dummy --dry-run -oyaml does not set CreationTimestamp.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can try w/o, but I do not think kops create -f mycluster.yaml works w/o it.

switch c.Output {
case OutputYaml:

var clusters []*api.Cluster
Copy link
Member

Choose a reason for hiding this comment

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

Hoist the common code out of the switch I think

@@ -1008,6 +1065,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
}
}

// Can we acutally get to this if??
Copy link
Member

Choose a reason for hiding this comment

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

Do you mean that targetName is always != "" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is targetName ever == "". I think it is always set, and the if statement is not needed

Copy link
Member

Choose a reason for hiding this comment

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

I think you're right, but separate PR probably

Copy link
Member

Choose a reason for hiding this comment

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

Can you pull this comment out of this PR?

@@ -215,6 +214,100 @@ func clusterOutputJson(clusters []*api.Cluster, out io.Writer) error {
return nil
}

// TODO refactor all output JSON methods to use this
Copy link
Member

Choose a reason for hiding this comment

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

Can we create two helpers:

func marshalMultipleToYaml(w io.Writer, obj runtime.Object...) error {

func marshalMultipleToJson(w io.Writer, obj runtime.Object...) error {

Should make this simpler

@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Nov 4, 2017
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Nov 4, 2017
@chrislovecnm chrislovecnm modified the milestones: backlog, 1.8.0 Nov 4, 2017
@chrislovecnm chrislovecnm force-pushed the create-yaml-or-json branch 3 times, most recently from 4185ca6 to 3ba6bfc Compare November 4, 2017 20:11
Copy link
Member

@justinsb justinsb left a comment

Choose a reason for hiding this comment

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

Generally looks good, just a few small fixes

}

var targetOptions = sets.NewString(cloudup.TargetCloudformation, cloudup.TargetDirect, cloudup.TargetTerraform)
var allTargetOptions = strings.Join(targetOptions.List(), ",")
Copy link
Member

Choose a reason for hiding this comment

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

targetOptions is unused? Can we put direct first, as it is the default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will remove the set then ...

@@ -987,6 +1013,39 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
return err
}

if c.DryRun {
var obj []runtime.Object
// if we do not set the ts we get creationTimestamp: null
Copy link
Member

Choose a reason for hiding this comment

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

That's what kubectl does, so can you add a comment on the consequence of creationTimestamp null

Copy link
Member

Choose a reason for hiding this comment

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

kubectl sets null, I think we should probably be doing the same

@@ -1008,6 +1065,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
}
}

// Can we acutally get to this if??
Copy link
Member

Choose a reason for hiding this comment

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

I think you're right, but separate PR probably

@@ -39,6 +40,11 @@ import (
type CreateInstanceGroupOptions struct {
Role string
Subnets []string
// DryRun we output data
Copy link
Member

Choose a reason for hiding this comment

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

Comment is a little obscure

cmd/kops/get.go Outdated
obj = append(obj, group)
}
if err := fullOutputJSON(out, obj...); err != nil {
return fmt.Errorf("error writing cluster yaml to stdout: %v", err)
Copy link
Member

Choose a reason for hiding this comment

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

json

cmd/kops/get.go Outdated
return err
}*/

var obj []runtime.Object
Copy link
Member

Choose a reason for hiding this comment

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

Hoist out of the loop please


default:
return fmt.Errorf("Unknown output format: %q", options.output)
return fmt.Errorf("unknown output format: %q", options.output)
Copy link
Member

Choose a reason for hiding this comment

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

So the reason for these being upper case is because they look better when displayed, and this is a CLI command object. It's the same way the go rules conflict with all our comments in apimachinery types.

I guess we should format the error forcing the first character to upper-case? But in another PR. Please no more case-switches in this PR though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will back them out, they bug me

func fullOutputJSON(out io.Writer, args ...runtime.Object) error {
argsLen := len(args)

if argsLen > 1 {
Copy link
Member

Choose a reason for hiding this comment

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

I think we should always write the array, even if it is empty. I don't think an empty string is valid JSON?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

JSON object is not an array. For instance when we create an ig, we just get a single object

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can always write an array, but at least with a single JSON object create -f works, with a JSON array it bombs

Copy link
Member

Choose a reason for hiding this comment

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

We discussed this; you are right - better to only write the array if there are multiple members. This way a single object is an object

return nil
}

func clusterOutputYAML(clusters []*api.Cluster, out io.Writer) error {
for i, cluster := range clusters {
// fullOutputJson outputs the marshalled YAML of a list of clusters and instance groups. It will handle
Copy link
Member

Choose a reason for hiding this comment

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

yaml

@chrislovecnm chrislovecnm force-pushed the create-yaml-or-json branch 2 times, most recently from 937d32f to 66e6f95 Compare November 4, 2017 22:36
@justinsb
Copy link
Member

justinsb commented Nov 4, 2017

Looks good, we just need to figure out if creationTimestamp should be set... I think not?

Added --dry-run for create_ig and create_cluster
@justinsb
Copy link
Member

justinsb commented Nov 4, 2017

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 4, 2017
@k8s-github-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: justinsb

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@k8s-github-robot k8s-github-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 4, 2017
@k8s-github-robot
Copy link

/test all [submit-queue is verifying that this PR is safe to merge]

@k8s-github-robot
Copy link

Automatic merge from submit-queue.

@k8s-github-robot k8s-github-robot merged commit 40a94a7 into kubernetes:master Nov 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants