blob: dc3a9454c1e11ae8134e32cd8ea2d4694ca672ba [file] [log] [blame]
// Copyright Istio 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 istioctl
import (
"bytes"
"fmt"
"strings"
"sync"
"time"
)
import (
"github.com/apache/dubbo-go-pixiu/istioctl/cmd"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/config/kube/crd"
"github.com/apache/dubbo-go-pixiu/pkg/test"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/resource"
"github.com/apache/dubbo-go-pixiu/pkg/test/scopes"
)
// We cannot invoke the istioctl library concurrently due to the number of global variables
// https://github.com/istio/istio/issues/37324
var invokeMutex sync.Mutex
type kubeComponent struct {
config Config
kubeconfig string
}
// Filenamer is an interface to avoid importing kubecluster package, instead build our own interface
// to extract kube context
type Filenamer interface {
Filename() string
}
func newKube(ctx resource.Context, config Config) (Instance, error) {
fn, ok := ctx.Clusters().GetOrDefault(config.Cluster).(Filenamer)
if !ok {
return nil, fmt.Errorf("cluster does not support fetching kube config")
}
n := &kubeComponent{
config: config,
kubeconfig: fn.Filename(),
}
return n, nil
}
// Invoke implements WaitForConfigs
func (c *kubeComponent) WaitForConfig(defaultNamespace string, configs string) error {
cfgs, _, err := crd.ParseInputs(configs)
if err != nil {
return fmt.Errorf("failed to parse input: %v", err)
}
for _, cfg := range cfgs {
ns := cfg.Namespace
if ns == "" {
ns = defaultNamespace
}
// TODO(https://github.com/istio/istio/issues/37148) increase timeout. Right now it fails often, so
// set it to low timeout to reduce impact
if out, stderr, err := c.Invoke([]string{"x", "wait", "-v", "--timeout=5s", cfg.GroupVersionKind.Kind, cfg.Name + "." + ns}); err != nil {
return fmt.Errorf("wait: %v\nout: %v\nerr: %v", err, out, stderr)
}
}
return nil
}
// Invoke implements Instance
func (c *kubeComponent) Invoke(args []string) (string, string, error) {
cmdArgs := append([]string{
"--kubeconfig",
c.kubeconfig,
}, args...)
var out bytes.Buffer
var err bytes.Buffer
start := time.Now()
invokeMutex.Lock()
rootCmd := cmd.GetRootCmd(cmdArgs)
rootCmd.SetOut(&out)
rootCmd.SetErr(&err)
fErr := rootCmd.Execute()
invokeMutex.Unlock()
scopes.Framework.Infof("istioctl (%v): completed after %.4fs", args, time.Since(start).Seconds())
if err.String() != "" {
scopes.Framework.Infof("istioctl error: %v", strings.TrimSpace(err.String()))
}
return out.String(), err.String(), fErr
}
// InvokeOrFail implements Instance
func (c *kubeComponent) InvokeOrFail(t test.Failer, args []string) (string, string) {
output, stderr, err := c.Invoke(args)
if err != nil {
t.Logf("Unwanted exception for 'istioctl %s': %v", strings.Join(args, " "), err)
t.Logf("Output:\n%v", output)
t.Logf("Error:\n%v", stderr)
t.FailNow()
}
return output, stderr
}