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

CLI: Adds install command #121

Merged
merged 1 commit into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
CLI: tkn hub install command
This adds install command in tkn hub, has 2 subcommand task and
pipeline. by default latest version is installed.
'--version' flag can be used to pass a specific version.
'--from' flag can be used to pass catalog name.
If a resource is already installed with the passed name, will return
an error.

Signed-off-by: Shivam Mukhade <smukhade@redhat.com>
  • Loading branch information
SM43 committed Dec 4, 2020
commit e046794a0cb2eb4b11672b8aa831cf3bb1213c01
24 changes: 10 additions & 14 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,29 @@ require (
github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.7.0
github.com/stretchr/testify v1.5.1
github.com/tektoncd/pipeline v0.15.2
github.com/tektoncd/pipeline v0.17.1-0.20201007165454-9611f3e4509e
go.uber.org/zap v1.15.0
goa.design/goa/v3 v3.2.2
goa.design/plugins/v3 v3.1.3
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20200812155832-6a926be9bd1d // indirect
golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/h2non/gock.v1 v1.0.15
gorm.io/driver/postgres v1.0.2
gorm.io/gorm v1.20.7
gotest.tools/v3 v3.0.2
k8s.io/apimachinery v0.17.6
k8s.io/apimachinery v0.19.0
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
knative.dev/pkg v0.0.0-20200702222342-ea4d6e985ba0
knative.dev/pkg v0.0.0-20200922164940-4bf40ad82aab
)

// Copied from Catlin
// Pin k8s deps to 1.17.6
// Pin k8s deps to 0.18.9
replace (
k8s.io/api => k8s.io/api v0.17.6
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.17.6
k8s.io/apimachinery => k8s.io/apimachinery v0.17.6
k8s.io/apiserver => k8s.io/apiserver v0.17.6
k8s.io/client-go => k8s.io/client-go v0.17.6
k8s.io/code-generator => k8s.io/code-generator v0.17.6
k8s.io/api => k8s.io/api v0.18.9
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.9
k8s.io/apimachinery => k8s.io/apimachinery v0.18.9
k8s.io/apiserver => k8s.io/apiserver v0.18.9
k8s.io/client-go => k8s.io/client-go v0.18.9
k8s.io/code-generator => k8s.io/code-generator v0.18.9
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29
)

Expand Down
408 changes: 322 additions & 86 deletions api/go.sum

Large diffs are not rendered by default.

181 changes: 181 additions & 0 deletions api/pkg/cli/cmd/install/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright © 2020 The Tekton 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 install

import (
"fmt"
"strings"

"github.com/spf13/cobra"
"github.com/tektoncd/hub/api/pkg/cli/app"
"github.com/tektoncd/hub/api/pkg/cli/flag"
"github.com/tektoncd/hub/api/pkg/cli/hub"
"github.com/tektoncd/hub/api/pkg/cli/installer"
"github.com/tektoncd/hub/api/pkg/cli/kube"
"github.com/tektoncd/hub/api/pkg/cli/printer"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

type options struct {
cli app.CLI
from string
version string
kind string
args []string
kc kube.Config
cs kube.ClientSet
hubRes hub.ResourceResult
resource *unstructured.Unstructured
}

var cmdExamples string = `
Install a %S of name 'foo':

tkn hub install %s foo

or

Install a %S of name 'foo' of version '0.3' from Catalog 'Tekton':

tkn hub install %s foo --version 0.3 --from tekton
`

func Command(cli app.CLI) *cobra.Command {

opts := &options{cli: cli}

cmd := &cobra.Command{
Use: "install",
Short: "Install a resource from a catalog by its kind, name and version",
Long: ``,
Annotations: map[string]string{
"commandType": "main",
},
SilenceUsage: true,
}
cmd.AddCommand(
commandForKind("task", opts),
)

cmd.PersistentFlags().StringVar(&opts.from, "from", "tekton", "Name of Catalog to which resource belongs.")
cmd.PersistentFlags().StringVar(&opts.version, "version", "", "Version of Resource")

cmd.PersistentFlags().StringVarP(&opts.kc.Path, "kubeconfig", "k", "", "Kubectl config file (default: $HOME/.kube/config)")
cmd.PersistentFlags().StringVarP(&opts.kc.Context, "context", "c", "", "Name of the kubeconfig context to use (default: kubectl config current-context)")
cmd.PersistentFlags().StringVarP(&opts.kc.Namespace, "namespace", "n", "", "Namespace to use (default: from $KUBECONFIG)")

return cmd
}

// commandForKind creates a cobra.Command that when run sets
// opts.Kind and opts.Args and invokes opts.run
func commandForKind(kind string, opts *options) *cobra.Command {

return &cobra.Command{
Use: kind,
Short: "Install " + kind + " from a catalog by its name and version",
Long: ``,
SilenceUsage: true,
Example: examples(kind),
Annotations: map[string]string{
"commandType": "main",
},
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.kind = kind
opts.args = args
return opts.run()
},
}
}

func (opts *options) run() error {

if err := opts.validate(); err != nil {
return err
}

hubClient := opts.cli.Hub()
opts.hubRes = hubClient.GetResource(hub.ResourceOption{
Name: opts.name(),
Catalog: opts.from,
Kind: opts.kind,
Version: opts.version,
})

manifest, err := opts.hubRes.Manifest()
if err != nil {
return err
}

// This allows fake clients to be inserted while testing
if opts.cs == nil {
opts.cs, err = kube.NewClientSet(opts.kc)
if err != nil {
return err
}
}

installer := installer.New(opts.cs)
opts.resource, err = installer.Install(manifest, opts.from, opts.cs.Namespace())
if err != nil {
return opts.errors(err)
}

out := opts.cli.Stream().Out
return printer.New(out).String(msg(opts.resource))
}

func msg(res *unstructured.Unstructured) string {
version := res.GetLabels()["app.kubernetes.io/version"]
return fmt.Sprintf("%s %s(%s) installed in %s namespace",
strings.Title(res.GetKind()), res.GetName(), version, res.GetNamespace())
}

func (opts *options) validate() error {
return flag.ValidateVersion(opts.version)
}

func (opts *options) name() string {
return strings.TrimSpace(opts.args[0])
}

func (opts *options) errors(err error) error {

if err == installer.ErrAlreadyExist {
res := opts.resource.GetName()
version, ok := opts.resource.GetLabels()["app.kubernetes.io/version"]
if ok {
res = res + fmt.Sprintf("(%s)", version)
}
return fmt.Errorf("%s %s already exists in %s namespace",
strings.Title(opts.resource.GetKind()), res, opts.cs.Namespace())
}

if strings.Contains(err.Error(), "mutation failed: cannot decode incoming new object") {
version, vErr := opts.hubRes.MinPipelinesVersion()
if vErr != nil {
return vErr
}
return fmt.Errorf("%v \nMake sure the pipeline version you are running is not lesser than %s and %s have correct spec fields",
err, version, opts.kind)
}
return err
}

func examples(kind string) string {
replacer := strings.NewReplacer("%s", kind, "%S", strings.Title(kind))
return replacer.Replace(cmdExamples)
}
Loading