linkerd2/multicluster/cmd/allow.go

128 lines
3.5 KiB
Go

package cmd
import (
"context"
"errors"
"fmt"
"github.com/linkerd/linkerd2/multicluster/static"
mccharts "github.com/linkerd/linkerd2/multicluster/values"
"github.com/linkerd/linkerd2/pkg/charts"
"github.com/linkerd/linkerd2/pkg/k8s"
"github.com/linkerd/linkerd2/pkg/version"
"github.com/spf13/cobra"
chartloader "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
type (
allowOptions struct {
namespace string
serviceAccountName string
ignoreCluster bool
}
)
func newAllowCommand() *cobra.Command {
opts := allowOptions{
namespace: defaultMulticlusterNamespace,
ignoreCluster: false,
}
cmd := &cobra.Command{
Hidden: false,
Use: "allow",
Short: "Outputs credential resources that allow service-mirror controllers to connect to this cluster",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
values, err := buildMulticlusterAllowValues(cmd.Context(), &opts)
if err != nil {
return err
}
// Render raw values and create chart config
rawValues, err := yaml.Marshal(values)
if err != nil {
return err
}
files := []*chartloader.BufferedFile{
{Name: chartutil.ChartfileName},
{Name: "templates/namespace.yaml"},
{Name: "templates/remote-access-service-mirror-rbac.yaml"},
}
chart := &charts.Chart{
Name: helmMulticlusterDefaultChartName,
Dir: helmMulticlusterDefaultChartName,
Namespace: controlPlaneNamespace,
RawValues: rawValues,
Files: files,
Fs: static.Templates,
}
buf, err := chart.RenderNoPartials()
if err != nil {
return err
}
stdout.Write(buf.Bytes())
stdout.Write([]byte("---\n"))
return nil
},
}
cmd.Flags().StringVar(&opts.namespace, "namespace", defaultMulticlusterNamespace, "The destination namespace for the service account.")
cmd.Flags().BoolVar(&opts.ignoreCluster, "ignore-cluster", false, "Ignore cluster configuration")
cmd.Flags().StringVar(&opts.serviceAccountName, "service-account-name", "", "The name of the multicluster access service account")
return cmd
}
func buildMulticlusterAllowValues(ctx context.Context, opts *allowOptions) (*mccharts.Values, error) {
kubeAPI, err := k8s.NewAPI(kubeconfigPath, kubeContext, impersonate, impersonateGroup, 0)
if err != nil {
return nil, err
}
if opts.namespace == "" {
return nil, errors.New("you need to specify a namespace")
}
if opts.serviceAccountName == "" {
return nil, errors.New("you need to specify a service account name")
}
if opts.namespace == controlPlaneNamespace {
return nil, errors.New("you need to setup the multicluster addons in a namespace different than the Linkerd one")
}
defaults, err := mccharts.NewInstallValues()
if err != nil {
return nil, err
}
defaults.Namespace = opts.namespace
defaults.LinkerdVersion = version.Version
defaults.Gateway = false
defaults.ServiceMirror = false
defaults.RemoteMirrorServiceAccount = true
defaults.RemoteMirrorServiceAccountName = opts.serviceAccountName
if !opts.ignoreCluster {
acc, err := kubeAPI.CoreV1().ServiceAccounts(defaults.Namespace).Get(ctx, defaults.RemoteMirrorServiceAccountName, metav1.GetOptions{})
if err == nil && acc != nil {
return nil, fmt.Errorf("Service account with name %s already exists, use --ignore-cluster for force operation", defaults.RemoteMirrorServiceAccountName)
}
if !kerrors.IsNotFound(err) {
return nil, err
}
}
return defaults, nil
}