mirror of https://github.com/linkerd/linkerd2.git
184 lines
5.7 KiB
Go
184 lines
5.7 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/golang/protobuf/ptypes"
|
|
"github.com/linkerd/linkerd2/cli/flag"
|
|
pb "github.com/linkerd/linkerd2/controller/gen/config"
|
|
charts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
|
|
"github.com/linkerd/linkerd2/pkg/healthcheck"
|
|
"github.com/linkerd/linkerd2/pkg/issuercerts"
|
|
"github.com/linkerd/linkerd2/pkg/k8s"
|
|
"github.com/linkerd/linkerd2/pkg/version"
|
|
"github.com/spf13/pflag"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/client-go/kubernetes"
|
|
)
|
|
|
|
func loadStoredValuesLegacy(ctx context.Context, k *k8s.KubernetesAPI) (*charts.Values, error) {
|
|
|
|
// We fetch the configs directly from kubernetes because we need to be able
|
|
// to upgrade/reinstall the control plane when the API is not available; and
|
|
// this also serves as a passive check that we have privileges to access this
|
|
// control plane.
|
|
_, configs, err := healthcheck.FetchLinkerdConfigMap(ctx, k, controlPlaneNamespace)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not fetch configs from kubernetes: %s", err)
|
|
}
|
|
repairConfigs(configs)
|
|
|
|
values, err := charts.NewValues()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
allStageFlags, allStageFlagSet := makeAllStageFlags(values)
|
|
installFlags, installFlagSet := makeInstallFlags(values)
|
|
upgradeFlags, installUpgradeFlagSet, err := makeInstallUpgradeFlags(values)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
proxyFlags, proxyFlagSet := makeProxyFlags(values)
|
|
|
|
flagSet := pflag.NewFlagSet("loaded_flags", pflag.ExitOnError)
|
|
flagSet.AddFlagSet(allStageFlagSet)
|
|
flagSet.AddFlagSet(installFlagSet)
|
|
flagSet.AddFlagSet(installUpgradeFlagSet)
|
|
flagSet.AddFlagSet(proxyFlagSet)
|
|
|
|
setFlagsFromInstall(flagSet, configs.GetInstall().GetFlags())
|
|
|
|
flags := flattenFlags(allStageFlags, installFlags, upgradeFlags, proxyFlags)
|
|
err = flag.ApplySetFlags(values, flags)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
idctx := configs.GetGlobal().GetIdentityContext()
|
|
if idctx.GetTrustDomain() != "" && idctx.GetTrustAnchorsPem() != "" {
|
|
err = fetchIdentityValues(ctx, k, idctx, values)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return values, nil
|
|
}
|
|
|
|
func setFlagsFromInstall(flags *pflag.FlagSet, installFlags []*pb.Install_Flag) {
|
|
for _, i := range installFlags {
|
|
if f := flags.Lookup(i.GetName()); f != nil && !f.Changed {
|
|
// The function recordFlags() stores the string representation of flags in the ConfigMap
|
|
// so a stringSlice is stored e.g. as [a,b].
|
|
// To avoid having f.Value.Set() interpreting that as a string we need to remove
|
|
// the brackets
|
|
value := i.GetValue()
|
|
if f.Value.Type() == "stringSlice" {
|
|
value = strings.Trim(value, "[]")
|
|
}
|
|
|
|
f.Value.Set(value)
|
|
f.Changed = true
|
|
}
|
|
}
|
|
}
|
|
|
|
func repairConfigs(configs *pb.All) {
|
|
// Repair the "install" section; install flags are updated separately
|
|
if configs.Install == nil {
|
|
configs.Install = &pb.Install{}
|
|
}
|
|
// ALWAYS update the CLI version to the most recent.
|
|
configs.Install.CliVersion = version.Version
|
|
|
|
// Repair the "proxy" section
|
|
if configs.Proxy == nil {
|
|
configs.Proxy = &pb.Proxy{}
|
|
}
|
|
if configs.Proxy.DebugImage == nil {
|
|
configs.Proxy.DebugImage = &pb.Image{}
|
|
}
|
|
if configs.GetProxy().GetDebugImage().GetImageName() == "" {
|
|
configs.Proxy.DebugImage.ImageName = k8s.DebugSidecarImage
|
|
}
|
|
if configs.GetProxy().GetDebugImageVersion() == "" {
|
|
configs.Proxy.DebugImageVersion = version.Version
|
|
}
|
|
}
|
|
|
|
// fetchIdentityValue checks the kubernetes API to fetch an existing
|
|
// linkerd identity configuration.
|
|
//
|
|
// This bypasses the public API so that we can access secrets and validate
|
|
// permissions.
|
|
func fetchIdentityValues(ctx context.Context, k kubernetes.Interface, idctx *pb.IdentityContext, values *charts.Values) error {
|
|
if idctx == nil {
|
|
return nil
|
|
}
|
|
|
|
if idctx.Scheme == "" {
|
|
// if this is empty, then we are upgrading from a version
|
|
// that did not support issuer schemes. Just default to the
|
|
// linkerd one.
|
|
idctx.Scheme = k8s.IdentityIssuerSchemeLinkerd
|
|
}
|
|
|
|
var trustAnchorsPEM string
|
|
var issuerData *issuercerts.IssuerCertData
|
|
var err error
|
|
|
|
trustAnchorsPEM = idctx.GetTrustAnchorsPem()
|
|
|
|
issuerData, err = fetchIssuer(ctx, k, trustAnchorsPEM, idctx.Scheme)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
clockSkewDuration, err := ptypes.Duration(idctx.GetClockSkewAllowance())
|
|
if err != nil {
|
|
return fmt.Errorf("could not convert clock skew protobuf Duration format into golang Duration: %s", err)
|
|
}
|
|
|
|
issuanceLifetimeDuration, err := ptypes.Duration(idctx.GetIssuanceLifetime())
|
|
if err != nil {
|
|
return fmt.Errorf("could not convert issuance Lifetime protobuf Duration format into golang Duration: %s", err)
|
|
}
|
|
|
|
values.GetGlobal().IdentityTrustAnchorsPEM = trustAnchorsPEM
|
|
values.Identity.Issuer.Scheme = idctx.Scheme
|
|
values.Identity.Issuer.ClockSkewAllowance = clockSkewDuration.String()
|
|
values.Identity.Issuer.IssuanceLifetime = issuanceLifetimeDuration.String()
|
|
if issuerData.Expiry != nil {
|
|
values.Identity.Issuer.CrtExpiry = *issuerData.Expiry
|
|
}
|
|
values.Identity.Issuer.TLS.KeyPEM = issuerData.IssuerKey
|
|
values.Identity.Issuer.TLS.CrtPEM = issuerData.IssuerCrt
|
|
|
|
return nil
|
|
}
|
|
|
|
func fetchIssuer(ctx context.Context, k kubernetes.Interface, trustPEM string, scheme string) (*issuercerts.IssuerCertData, error) {
|
|
var (
|
|
issuerData *issuercerts.IssuerCertData
|
|
err error
|
|
)
|
|
switch scheme {
|
|
case string(corev1.SecretTypeTLS):
|
|
// Do not return external issuer certs as no need of storing them in config and upgrade secrets
|
|
// Also contradicts condition in https://github.com/linkerd/linkerd2/blob/main/cli/cmd/options.go#L550
|
|
return &issuercerts.IssuerCertData{}, nil
|
|
default:
|
|
issuerData, err = issuercerts.FetchIssuerData(ctx, k, trustPEM, controlPlaneNamespace)
|
|
if issuerData != nil && issuerData.TrustAnchors != trustPEM {
|
|
issuerData.TrustAnchors = trustPEM
|
|
}
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return issuerData, nil
|
|
}
|