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

add git ops options #1122

Merged
merged 15 commits into from
Jan 14, 2021
6 changes: 6 additions & 0 deletions docs/cmd/kn_service_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ kn service create NAME --image IMAGE
# [https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/]
# [https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/]
kn service create s4gpu --image knativesamples/hellocuda-go --request memory=250Mi,cpu=200m --limit nvidia.com/gpu=1

# Create the service in offline mode instead of kubernetes cluster
kn service create gitopstest -n test-ns --image knativesamples/helloworld --target=/user/knfiles
kn service create gitopstest --image knativesamples/helloworld --target=/user/knfiles/test.yaml
kn service create gitopstest --image knativesamples/helloworld --target=/user/knfiles/test.json
```

### Options
Expand Down Expand Up @@ -88,6 +93,7 @@ kn service create NAME --image IMAGE
--scale-max int Maximum number of replicas.
--scale-min int Minimum number of replicas.
--service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
--target string work on local directory instead of a remote cluster
--user int The user ID to run the container (e.g., 1001).
--volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
--wait Wait for 'service create' operation to be completed. (default true)
Expand Down
6 changes: 6 additions & 0 deletions docs/cmd/kn_service_delete.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ kn service delete NAME [NAME ...]

# Delete all services in 'ns1' namespace
kn service delete --all -n ns1

# Delete the services in offline mode instead of kubernetes cluster
kn service delete test -n test-ns --target=/user/knfiles
kn service delete test --target=/user/knfiles/test.yaml
kn service delete test --target=/user/knfiles/test.json
```

### Options
Expand All @@ -31,6 +36,7 @@ kn service delete NAME [NAME ...]
-h, --help help for delete
-n, --namespace string Specify the namespace to operate in.
--no-wait Do not wait for 'service delete' operation to be completed. (default true)
--target string work on local directory instead of a remote cluster
--wait Wait for 'service delete' operation to be completed.
--wait-timeout int Seconds to wait before giving up on waiting for service to be deleted. (default 600)
```
Expand Down
6 changes: 6 additions & 0 deletions docs/cmd/kn_service_describe.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ kn service describe NAME

# Print only service URL
kn service describe svc -o url

# Describe the services in offline mode instead of kubernetes cluster
kn service describe test -n test-ns --target=/user/knfiles
kn service describe test --target=/user/knfiles/test.yaml
kn service describe test --target=/user/knfiles/test.json
```

### Options
Expand All @@ -31,6 +36,7 @@ kn service describe NAME
-h, --help help for describe
-n, --namespace string Specify the namespace to operate in.
-o, --output string Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file|url.
--target string work on local directory instead of a remote cluster
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
-v, --verbose More output.
```
Expand Down
7 changes: 7 additions & 0 deletions docs/cmd/kn_service_list.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ kn service list

# List service 'web'
kn service list web

# List the services in offline mode instead of kubernetes cluster
kn service list --target=/user/knfiles
kn service list --target=/user/knfiles/test.json
kn service list --target=/user/knfiles/test.yaml
kn service list -n test-ns --target=/user/knfiles
```

### Options
Expand All @@ -33,6 +39,7 @@ kn service list
-n, --namespace string Specify the namespace to operate in.
--no-headers When using the default output format, don't print headers (default: print headers).
-o, --output string Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
--target string work on local directory instead of a remote cluster
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
```

Expand Down
6 changes: 6 additions & 0 deletions docs/cmd/kn_service_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ kn service update NAME

# Add tag 'test' to echo-v3 revision with 10% traffic and rest to latest ready revision of service
kn service update svc --tag echo-v3=test --traffic test=10,@latest=90

# Update the service in offline mode instead of kubernetes cluster
kn service update gitopstest -n test-ns --env KEY1=VALUE1 --target=/user/knfiles
kn service update gitopstest --env KEY1=VALUE1 --target=/user/knfiles/test.yaml
kn service update gitopstest --env KEY1=VALUE1 --target=/user/knfiles/test.json
```

### Options
Expand Down Expand Up @@ -72,6 +77,7 @@ kn service update NAME
--scale-min int Minimum number of replicas.
--service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
--tag strings Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. This flag can be specified multiple times.
--target string work on local directory instead of a remote cluster
--traffic strings Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.
--untag strings Untag revision (format: --untag tagName). This flag can be specified multiple times.
--user int The user ID to run the container (e.g., 1001).
Expand Down
6 changes: 6 additions & 0 deletions pkg/kn/commands/human_readable_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"time"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/duration"
hprinters "knative.dev/client/pkg/printers"
Expand Down Expand Up @@ -113,3 +114,8 @@ func TranslateTimestampSince(timestamp metav1.Time) string {
}
return duration.HumanDuration(time.Since(timestamp.Time))
}

// AddGitOpsFlags adds flags to enable gitops mode
func AddGitOpsFlags(flags *pflag.FlagSet) {
itsmurugappan marked this conversation as resolved.
Show resolved Hide resolved
flags.String("target", "", "work on local directory instead of a remote cluster")
Copy link
Contributor

Choose a reason for hiding this comment

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

A little formatting nit to align with the rest.

Suggested change
flags.String("target", "", "work on local directory instead of a remote cluster")
flags.String("target", "", "Work on local directory instead of a remote cluster.")

Copy link
Contributor

@dsimansk dsimansk Dec 15, 2020

Choose a reason for hiding this comment

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

On a second thought I wonder if the message shouldn't be more descriptive/verbose. The following is just an example feel free to change or ignore it. :)

Create Knative resources in local directory or file instead of a remote cluster. Default mode is current directory, in addition path to custom directory or file extensions .yaml, .yml, .json are accepted. 

@rhuss I recall you've mentioned the feature is experimental. Therefore we should add (experimental) suffix at the end of description, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we should mark it as experimental and we should definitely include it for 0.20

Copy link
Contributor

Choose a reason for hiding this comment

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

To not lose to much time, lets merge this and create a followup PR to add the indication that this feature is experimental in a followup PR.

}
2 changes: 1 addition & 1 deletion pkg/kn/commands/service/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func NewServiceApplyCommand(p *commands.KnParams) *cobra.Command {

return showUrl(client, service.Name, "unchanged", "", cmd.OutOrStdout())
}
return waitIfRequested(client, service.Name, waitFlags, waitDoing, waitVerb, cmd.OutOrStdout())
return waitIfRequested(client, waitFlags, service.Name, waitDoing, waitVerb, "", cmd.OutOrStdout())
},
}
commands.AddNamespaceFlags(serviceApplyCommand.Flags(), false)
Expand Down
29 changes: 17 additions & 12 deletions pkg/kn/commands/service/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,12 @@ var create_example = `
# Create a service with 250MB memory, 200m CPU requests and a GPU resource limit
# [https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/]
# [https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/]
kn service create s4gpu --image knativesamples/hellocuda-go --request memory=250Mi,cpu=200m --limit nvidia.com/gpu=1`
kn service create s4gpu --image knativesamples/hellocuda-go --request memory=250Mi,cpu=200m --limit nvidia.com/gpu=1

# Create the service in offline mode instead of kubernetes cluster
kn service create gitopstest -n test-ns --image knativesamples/helloworld --target=/user/knfiles
kn service create gitopstest --image knativesamples/helloworld --target=/user/knfiles/test.yaml
kn service create gitopstest --image knativesamples/helloworld --target=/user/knfiles/test.json`

func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
var editFlags ConfigurationEditFlags
Expand Down Expand Up @@ -106,8 +111,8 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
if err != nil {
return err
}

client, err := p.NewServingClient(namespace)
targetFlag := cmd.Flag("target").Value.String()
client, err := newServingClient(p, namespace, targetFlag)
if err != nil {
return err
}
Expand All @@ -123,9 +128,9 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
"cannot create service '%s' in namespace '%s' "+
"because the service already exists and no --force option was given", service.Name, namespace)
}
err = replaceService(client, service, waitFlags, out)
err = replaceService(client, service, waitFlags, out, targetFlag)
} else {
err = createService(client, service, waitFlags, out)
err = createService(client, service, waitFlags, out, targetFlag)
}
if err != nil {
return err
Expand All @@ -134,34 +139,34 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
},
}
commands.AddNamespaceFlags(serviceCreateCommand.Flags(), false)
commands.AddGitOpsFlags(serviceCreateCommand.Flags())
editFlags.AddCreateFlags(serviceCreateCommand)
waitFlags.AddConditionWaitFlags(serviceCreateCommand, commands.WaitDefaultTimeout, "create", "service", "ready")
return serviceCreateCommand
}

func createService(client clientservingv1.KnServingClient, service *servingv1.Service, waitFlags commands.WaitFlags, out io.Writer) error {
func createService(client clientservingv1.KnServingClient, service *servingv1.Service, waitFlags commands.WaitFlags, out io.Writer, targetFlag string) error {
err := client.CreateService(service)
if err != nil {
return err
}

return waitIfRequested(client, service.Name, waitFlags, "Creating", "created", out)
return waitIfRequested(client, waitFlags, service.Name, "Creating", "created", targetFlag, out)
}

func replaceService(client clientservingv1.KnServingClient, service *servingv1.Service, waitFlags commands.WaitFlags, out io.Writer) error {
func replaceService(client clientservingv1.KnServingClient, service *servingv1.Service, waitFlags commands.WaitFlags, out io.Writer, targetFlag string) error {
err := prepareAndUpdateService(client, service)
if err != nil {
return err
}
return waitIfRequested(client, service.Name, waitFlags, "Replacing", "replaced", out)
return waitIfRequested(client, waitFlags, service.Name, "Replacing", "replaced", targetFlag, out)
}

func waitIfRequested(client clientservingv1.KnServingClient, serviceName string, waitFlags commands.WaitFlags, verbDoing string, verbDone string, out io.Writer) error {
if !waitFlags.Wait {
func waitIfRequested(client clientservingv1.KnServingClient, waitFlags commands.WaitFlags, serviceName, verbDoing, verbDone, targetFlag string, out io.Writer) error {
if !waitFlags.Wait || targetFlag != "" {
fmt.Fprintf(out, "Service '%s' %s in namespace '%s'.\n", serviceName, verbDone, client.Namespace())
return nil
}

fmt.Fprintf(out, "%s service '%s' in namespace '%s':\n", verbDoing, serviceName, client.Namespace())
return waitForServiceToGetReady(client, serviceName, waitFlags.TimeoutInSeconds, verbDone, out)
}
Expand Down
10 changes: 8 additions & 2 deletions pkg/kn/commands/service/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
kn service delete svc2 -n ns1

# Delete all services in 'ns1' namespace
kn service delete --all -n ns1`,
kn service delete --all -n ns1

# Delete the services in offline mode instead of kubernetes cluster
kn service delete test -n test-ns --target=/user/knfiles
kn service delete test --target=/user/knfiles/test.yaml
kn service delete test --target=/user/knfiles/test.json`,

RunE: func(cmd *cobra.Command, args []string) error {
all, err := cmd.Flags().GetBool("all")
Expand All @@ -62,7 +67,7 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
if err != nil {
return err
}
client, err := p.NewServingClient(namespace)
client, err := newServingClient(p, namespace, cmd.Flag("target").Value.String())
if err != nil {
return err
}
Expand Down Expand Up @@ -100,6 +105,7 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command {
flags := serviceDeleteCommand.Flags()
flags.Bool("all", false, "Delete all services in a namespace.")
commands.AddNamespaceFlags(serviceDeleteCommand.Flags(), false)
commands.AddGitOpsFlags(serviceDeleteCommand.Flags())
waitFlags.AddConditionWaitFlags(serviceDeleteCommand, commands.WaitDefaultTimeout, "delete", "service", "deleted")
return serviceDeleteCommand
}
Expand Down
10 changes: 8 additions & 2 deletions pkg/kn/commands/service/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ var describe_example = `
kn service describe svc -o yaml

# Print only service URL
kn service describe svc -o url`
kn service describe svc -o url

# Describe the services in offline mode instead of kubernetes cluster
kn service describe test -n test-ns --target=/user/knfiles
kn service describe test --target=/user/knfiles/test.yaml
kn service describe test --target=/user/knfiles/test.json`

// NewServiceDescribeCommand returns a new command for describing a service.
func NewServiceDescribeCommand(p *commands.KnParams) *cobra.Command {
Expand All @@ -102,7 +107,7 @@ func NewServiceDescribeCommand(p *commands.KnParams) *cobra.Command {
return err
}

client, err := p.NewServingClient(namespace)
client, err := newServingClient(p, namespace, cmd.Flag("target").Value.String())
if err != nil {
return err
}
Expand Down Expand Up @@ -141,6 +146,7 @@ func NewServiceDescribeCommand(p *commands.KnParams) *cobra.Command {
}
flags := command.Flags()
commands.AddNamespaceFlags(flags, false)
commands.AddGitOpsFlags(flags)
flags.BoolP("verbose", "v", false, "More output.")
machineReadablePrintFlags.AddFlags(command)
command.Flag("output").Usage = fmt.Sprintf("Output format. One of: %s.", strings.Join(append(machineReadablePrintFlags.AllowedFormats(), "url"), "|"))
Expand Down
2 changes: 1 addition & 1 deletion pkg/kn/commands/service/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func importWithOwnerRef(client clientservingv1.KnServingClient, filename string,
}
}

err = waitIfRequested(client, serviceName, waitFlags, "Importing", "imported", out)
err = waitIfRequested(client, waitFlags, serviceName, "Importing", "imported", "", out)
if err != nil {
return err
}
Expand Down
12 changes: 10 additions & 2 deletions pkg/kn/commands/service/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,20 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command {
kn service list -o json

# List service 'web'
kn service list web`,
kn service list web

# List the services in offline mode instead of kubernetes cluster
kn service list --target=/user/knfiles
kn service list --target=/user/knfiles/test.json
kn service list --target=/user/knfiles/test.yaml
kn service list -n test-ns --target=/user/knfiles`,

RunE: func(cmd *cobra.Command, args []string) error {
namespace, err := p.GetNamespace(cmd)
if err != nil {
return err
}
client, err := p.NewServingClient(namespace)
client, err := newServingClient(p, namespace, cmd.Flag("target").Value.String())
if err != nil {
return err
}
Expand Down Expand Up @@ -81,6 +88,7 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command {
},
}
commands.AddNamespaceFlags(serviceListCommand.Flags(), true)
commands.AddGitOpsFlags(serviceListCommand.Flags())
serviceListFlags.AddFlags(serviceListCommand)
return serviceListCommand
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/kn/commands/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,10 @@ func showUrl(client clientservingv1.KnServingClient, serviceName string, origina

return nil
}

func newServingClient(p *commands.KnParams, namespace, dir string) (clientservingv1.KnServingClient, error) {
if dir != "" {
return p.NewGitopsServingClient(namespace, dir)
}
return p.NewServingClient(namespace)
}
14 changes: 10 additions & 4 deletions pkg/kn/commands/service/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ var updateExample = `
kn service update svc --untag testing --tag @latest=staging

# Add tag 'test' to echo-v3 revision with 10% traffic and rest to latest ready revision of service
kn service update svc --tag echo-v3=test --traffic test=10,@latest=90`
kn service update svc --tag echo-v3=test --traffic test=10,@latest=90

# Update the service in offline mode instead of kubernetes cluster
kn service update gitopstest -n test-ns --env KEY1=VALUE1 --target=/user/knfiles
kn service update gitopstest --env KEY1=VALUE1 --target=/user/knfiles/test.yaml
kn service update gitopstest --env KEY1=VALUE1 --target=/user/knfiles/test.json`

func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
var editFlags ConfigurationEditFlags
Expand All @@ -67,8 +72,8 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
if err != nil {
return err
}

client, err := p.NewServingClient(namespace)
targetFlag := cmd.Flag("target").Value.String()
client, err := newServingClient(p, namespace, targetFlag)
if err != nil {
return err
}
Expand Down Expand Up @@ -109,7 +114,7 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
}

out := cmd.OutOrStdout()
if waitFlags.Wait {
if waitFlags.Wait && targetFlag == "" {
fmt.Fprintf(out, "Updating Service '%s' in namespace '%s':\n", args[0], namespace)
fmt.Fprintln(out, "")
err := waitForService(client, name, out, waitFlags.TimeoutInSeconds)
Expand All @@ -131,6 +136,7 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
}

commands.AddNamespaceFlags(serviceUpdateCommand.Flags(), false)
commands.AddGitOpsFlags(serviceUpdateCommand.Flags())
editFlags.AddUpdateFlags(serviceUpdateCommand)
waitFlags.AddConditionWaitFlags(serviceUpdateCommand, commands.WaitDefaultTimeout, "update", "service", "ready")
trafficFlags.Add(serviceUpdateCommand)
Expand Down
Loading