// Copyright (c) 2020 Gitpod GmbH. All rights reserved. // Licensed under the GNU Affero General Public License (AGPL). // See License.AGPL.txt in the project root for license information. package cmd import ( "bytes" "fmt" "io" "os" "os/exec" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" "golang.org/x/xerrors" "k8s.io/apimachinery/pkg/util/yaml" "github.com/gitpod-io/gitpod/common-go/log" "github.com/gitpod-io/gitpod/ws-manager/pkg/test" ) // integrationTestSetupCmd represents the integrationTestSetup command var integrationTestSetupCmd = &cobra.Command{ Use: "objs ", Short: "Get Kubernetes objects that need to be present in a namespace for integration tests", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { kubecfgfn, _ := cmd.Parent().PersistentFlags().GetString("kubeconfig") _, namespace, err := test.GetIntegrationTestClient(kubecfgfn) if err != nil { log.WithError(err).Fatal("cannot get kubernetes client") } err = getIntegrationTestPrerequisiteObjects(os.Stdout, namespace, args[0], "wsman-test") if err != nil { log.WithError(err).Fatal("cannot prepare namespace") } }, } func init() { integrationTestCmd.AddCommand(integrationTestSetupCmd) } var desiredObjTypes = []string{ "ServiceAccount", "PodSecurityPolicy", } func getIntegrationTestPrerequisiteObjects(out io.Writer, namespace, gpHelmChartPath, version string) error { var helm string for _, c := range []string{"helm3", "helm"} { if _, err := exec.LookPath(c); err == nil { helm = c break } } if helm == "" { return xerrors.Errorf("no helm executable found in path") } // This command renders the helm template and selects everything workspace related. // The "workspace selector" is a heuristic that seems to work well. var ( eg errgroup.Group ri, ro = io.Pipe() ) eg.Go(func() error { helmCmd := exec.Command(helm, "template", "--set", "version="+version, "-n", namespace, ".") helmCmd.Dir = gpHelmChartPath helmCmd.Stdout = ro helmCmd.Stderr = os.Stderr err := helmCmd.Run() if err != nil { return xerrors.Errorf("cannot run helm: %w", err) } ro.Close() return nil }) eg.Go(func() error { dr := yaml.NewDocumentDecoder(io.NopCloser(ri)) buf := make([]byte, 100*4096) for { n, err := dr.Read(buf) if err == io.EOF { break } if err != nil { return xerrors.Errorf("cannot read YAML document: %w", err) } var ingest bool for _, dot := range desiredObjTypes { if !bytes.Contains(buf[0:n], []byte("workspace")) { continue } if !bytes.Contains(buf[0:n], []byte(dot)) { continue } ingest = true break } if !ingest { continue } fmt.Fprintf(out, "\n---\n") _, err = out.Write(buf[0:n]) if err != nil { return err } } return nil }) err := eg.Wait() if err != nil { return err } return nil }