Remove legacy upgrade and it's references (#7309)

With [linkerd2#5008](https://github.com/linkerd/linkerd2/issues/5008) and associated PRs, we changed the way configuration is handled by storing a helm values struct inside of the configmap.

Now that we have had one stable release with new configuration, were no longer use and need to maintain the legacy config. This commit removes all the associated logic, protobuf files, and references.

Changes Include:

- Removed [`proto/config/config.proto`](https://github.com/linkerd/linkerd2/blob/main/proto/config/config.proto)
- Changed [`bin/protoc-go.sh`](https://github.com/linkerd/linkerd2/blob/main/bin/protoc-go.sh) to not include `config.proto`
- Changed [`FetchLinkerdConfigMap()`](741fde679b/pkg/healthcheck/healthcheck.go (L1768)) in `healthcheck.go` to return only the configmap, with the pb type.
- Changed [`FetchCurrentConfiguration()`](741fde679b/pkg/healthcheck/healthcheck.go (L1647)) only unmarshal and use helm value struct from configmap (as a follow-up to the todo above; note that there's already a todo here to refactor the function once value struct is the default, which has already happened)
- Removed [`upgrade_legacy.go`](https://github.com/linkerd/linkerd2/blob/main/cli/cmd/upgrade_legacy.go)

Signed-off-by: Krzysztof Dryś <krzysztofdrys@gmail.com>
This commit is contained in:
Krzysztof Dryś 2021-11-29 15:38:58 +01:00 committed by GitHub
parent eb2f9e53be
commit f92e77f7f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 134 additions and 1999 deletions

View File

@ -11,7 +11,6 @@ rm -rf controller/gen/common controller/gen/config viz/metrics-api/gen viz/tap/g
mkdir -p controller/gen/common/net viz/metrics-api/gen/viz viz/tap/gen/tap
"$bindir"/protoc -I proto --go_out=paths=source_relative:controller/gen proto/common/net.proto
"$bindir"/protoc -I proto --go_out=paths=source_relative:controller/gen proto/config/config.proto
"$bindir"/protoc -I proto -I viz/metrics-api/proto --go_out=paths=source_relative:viz/metrics-api/gen viz/metrics-api/proto/viz.proto
"$bindir"/protoc -I proto -I viz/metrics-api/proto --go-grpc_out=paths=source_relative:viz/metrics-api/gen/viz viz/metrics-api/proto/viz.proto
"$bindir"/protoc -I proto -I viz/tap/proto -I viz/metrics-api/proto --go_out=paths=source_relative:viz/tap/gen viz/tap/proto/viz_tap.proto

View File

@ -8,10 +8,13 @@ import (
"regexp"
"time"
"github.com/golang/protobuf/ptypes"
pb "github.com/linkerd/linkerd2/controller/gen/config"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
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/cobra"
@ -127,16 +130,16 @@ func repair(ctx context.Context, forced bool) error {
if err != nil {
return fmt.Errorf("Failed to parse IssuanceLifetime from linkerd-config: %s", err)
}
idCtx := pb.IdentityContext{
TrustAnchorsPem: values.IdentityTrustAnchorsPEM,
Scheme: values.Identity.Issuer.Scheme,
ClockSkewAllowance: ptypes.DurationProto(clockSkewDuration),
IssuanceLifetime: ptypes.DurationProto(issuanceLifetime),
TrustDomain: values.IdentityTrustDomain,
idCtx := identityContext{
trustAnchorsPem: values.IdentityTrustAnchorsPEM,
scheme: values.Identity.Issuer.Scheme,
clockSkewAllowance: clockSkewDuration,
issuanceLifetime: issuanceLifetime,
trustDomain: values.IdentityTrustDomain,
}
// Populate identity values
err = fetchIdentityValues(ctx, k8sAPI, &idCtx, &values)
err = fetchIdentityValues(ctx, k8sAPI, idCtx, &values)
if err != nil {
return fmt.Errorf("Failed to load issuer credentials: %s", err)
}
@ -185,3 +188,68 @@ func resetVersion(values *linkerd2.Values) error {
values.LinkerdVersion = defaults.LinkerdVersion
return nil
}
type identityContext struct {
trustAnchorsPem string
scheme string
clockSkewAllowance time.Duration
issuanceLifetime time.Duration
trustDomain string
}
// 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 identityContext, values *charts.Values) error {
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.trustAnchorsPem
issuerData, err = fetchIssuer(ctx, k, trustAnchorsPEM, idctx.scheme)
if err != nil {
return err
}
values.IdentityTrustAnchorsPEM = trustAnchorsPEM
values.Identity.Issuer.Scheme = idctx.scheme
values.Identity.Issuer.ClockSkewAllowance = idctx.clockSkewAllowance.String()
values.Identity.Issuer.IssuanceLifetime = idctx.issuanceLifetime.String()
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
}

View File

@ -265,19 +265,10 @@ func upgrade(ctx context.Context, k *k8s.KubernetesAPI, flags []flag.Flag, stage
if err != nil {
return bytes.Buffer{}, fmt.Errorf("failed to load stored values: %w", err)
}
// If there is no linkerd-config-overrides secret, assume we are upgrading
// from a version of Linkerd prior to the introduction of this secret. In
// this case we load the values from the legacy linkerd-config configmap.
if values == nil {
values, err = loadStoredValuesLegacy(ctx, k)
if err != nil {
return bytes.Buffer{}, err
}
}
// If values is still nil, then neither the linkerd-config-overrides secret
// nor the legacy values were found. This means either means that Linkerd
// was installed with Helm or that the installation needs to be repaired.
// If values is still nil, then the linkerd-config-overrides secret was not found.
// This means either means that Linkerd was installed with Helm or that the installation
// needs to be repaired.
if values == nil {
return bytes.Buffer{}, errors.New(
`Could not find the Linkerd config. If Linkerd was installed with Helm, please

View File

@ -1,183 +0,0 @@
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)
}
if configs == nil {
return nil, nil
}
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.IdentityTrustAnchorsPEM = trustAnchorsPEM
values.Identity.Issuer.Scheme = idctx.Scheme
values.Identity.Issuer.ClockSkewAllowance = clockSkewDuration.String()
values.Identity.Issuer.IssuanceLifetime = issuanceLifetimeDuration.String()
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
}

View File

@ -203,8 +203,7 @@ func getServiceOpaquePortsAnnotation(svc *corev1.Service) (map[uint32]struct{},
func parseServiceOpaquePorts(annotation string, sps []corev1.ServicePort) []string {
portRanges := util.GetPortRanges(annotation)
var values []string
for _, portRange := range portRanges {
pr := portRange.GetPortRange()
for _, pr := range portRanges {
port, named := isNamed(pr, sps)
if named {
values = append(values, strconv.Itoa(int(port)))

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ import (
"time"
pkgK8s "github.com/linkerd/linkerd2/controller/k8s"
"github.com/linkerd/linkerd2/pkg/healthcheck"
"github.com/linkerd/linkerd2/pkg/config"
"github.com/linkerd/linkerd2/pkg/k8s"
"github.com/linkerd/linkerd2/pkg/version"
promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
@ -29,7 +29,7 @@ type containerMeta struct {
func K8sValues(ctx context.Context, kubeAPI *k8s.KubernetesAPI, controlPlaneNamespace string) url.Values {
v := url.Values{}
cm, _, err := healthcheck.FetchLinkerdConfigMap(ctx, kubeAPI, controlPlaneNamespace)
cm, err := config.FetchLinkerdConfigMap(ctx, kubeAPI, controlPlaneNamespace)
if err != nil {
log.Errorf("Failed to fetch linkerd-config: %s", err)
} else {

View File

@ -1,13 +1,15 @@
package config
import (
"context"
"fmt"
"io/ioutil"
"strings"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
pb "github.com/linkerd/linkerd2/controller/gen/config"
"github.com/linkerd/linkerd2/pkg/k8s"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
log "github.com/sirupsen/logrus"
"sigs.k8s.io/yaml"
@ -28,49 +30,6 @@ func Values(filepath string) (*l5dcharts.Values, error) {
return values, err
}
func unmarshal(json string, msg proto.Message) error {
// If a config is missing, then just leave the message as nil and return
// without an error.
if json == "" {
return nil
}
// If we're using older code to read a newer config, blowing up during decoding
// is not helpful. We should detect that through other means.
u := jsonpb.Unmarshaler{AllowUnknownFields: true}
return u.Unmarshal(strings.NewReader(json), msg)
}
// FromConfigMap builds a configuration by reading a map with the keys "global",
// "proxy", and "install" each containing JSON values. If none of these keys
// exist, FromConfigMap will return nil. This likely indicates that the
// installed version of Linkerd is stable-2.9.0 or later which uses a different
// config format.
func FromConfigMap(configMap map[string]string) (*pb.All, error) {
c := &pb.All{Global: &pb.Global{}, Proxy: &pb.Proxy{}, Install: &pb.Install{}}
global, globalOk := configMap["global"]
proxy, proxyOk := configMap["proxy"]
install, installOk := configMap["install"]
if !globalOk && !proxyOk && !installOk {
return nil, nil
}
if err := unmarshal(global, c.Global); err != nil {
return nil, fmt.Errorf("invalid global config: %s", err)
}
if err := unmarshal(proxy, c.Proxy); err != nil {
return nil, fmt.Errorf("invalid proxy config: %s", err)
}
if err := unmarshal(install, c.Install); err != nil {
return nil, fmt.Errorf("invalid install config: %s", err)
}
return c, nil
}
// RemoveGlobalFieldIfPresent removes the `global` node and
// attaches the children nodes there.
func RemoveGlobalFieldIfPresent(bytes []byte) ([]byte, error) {
@ -101,106 +60,12 @@ func RemoveGlobalFieldIfPresent(bytes []byte) ([]byte, error) {
return bytes, nil
}
// ToValues converts configuration into a Values struct, i.e to be consumed by check
// TODO: Remove this once the newer configuration becomes the default i.e 2.10
func ToValues(configs *pb.All) *l5dcharts.Values {
// convert install flags into values
values := &l5dcharts.Values{
CNIEnabled: configs.GetGlobal().GetCniEnabled(),
Namespace: configs.GetGlobal().GetLinkerdNamespace(),
IdentityTrustAnchorsPEM: configs.GetGlobal().GetIdentityContext().GetTrustAnchorsPem(),
IdentityTrustDomain: configs.GetGlobal().GetIdentityContext().GetTrustDomain(),
ClusterDomain: configs.GetGlobal().GetClusterDomain(),
ClusterNetworks: configs.GetProxy().GetDestinationGetNetworks(),
LinkerdVersion: configs.GetGlobal().GetVersion(),
Proxy: &l5dcharts.Proxy{
Image: &l5dcharts.Image{
Name: configs.GetProxy().GetProxyImage().GetImageName(),
PullPolicy: configs.GetProxy().GetProxyImage().GetPullPolicy(),
Version: configs.GetProxy().GetProxyVersion(),
},
Ports: &l5dcharts.Ports{
Control: int32(configs.GetProxy().GetControlPort().GetPort()),
Inbound: int32(configs.GetProxy().GetInboundPort().GetPort()),
Admin: int32(configs.GetProxy().GetAdminPort().GetPort()),
Outbound: int32(configs.GetProxy().GetOutboundPort().GetPort()),
},
Resources: &l5dcharts.Resources{
CPU: l5dcharts.Constraints{
Limit: configs.GetProxy().GetResource().GetLimitCpu(),
Request: configs.GetProxy().GetResource().GetRequestCpu(),
},
Memory: l5dcharts.Constraints{
Limit: configs.GetProxy().GetResource().GetLimitMemory(),
Request: configs.GetProxy().GetResource().GetRequestMemory(),
},
},
EnableExternalProfiles: !configs.Proxy.GetDisableExternalProfiles(),
LogFormat: configs.GetProxy().GetLogFormat(),
OutboundConnectTimeout: configs.GetProxy().GetOutboundConnectTimeout(),
InboundConnectTimeout: configs.GetProxy().GetInboundConnectTimeout(),
},
ProxyInit: &l5dcharts.ProxyInit{
IgnoreInboundPorts: toString(configs.GetProxy().GetIgnoreInboundPorts()),
IgnoreOutboundPorts: toString(configs.GetProxy().GetIgnoreOutboundPorts()),
Image: &l5dcharts.Image{
Name: configs.GetProxy().GetProxyInitImage().GetImageName(),
PullPolicy: configs.GetProxy().GetProxyInitImage().GetPullPolicy(),
Version: configs.GetProxy().GetProxyInitImageVersion(),
},
},
Identity: &l5dcharts.Identity{
Issuer: &l5dcharts.Issuer{
Scheme: configs.GetGlobal().GetIdentityContext().GetScheme(),
},
},
DebugContainer: &l5dcharts.DebugContainer{
Image: &l5dcharts.Image{
Name: configs.GetProxy().GetDebugImage().GetImageName(),
PullPolicy: configs.GetProxy().GetDebugImage().GetPullPolicy(),
Version: configs.GetProxy().GetDebugImageVersion(),
},
},
// FetchLinkerdConfigMap retrieves the `linkerd-config` ConfigMap from
// Kubernetes.
func FetchLinkerdConfigMap(ctx context.Context, k kubernetes.Interface, controlPlaneNamespace string) (*corev1.ConfigMap, error) {
cm, err := k.CoreV1().ConfigMaps(controlPlaneNamespace).Get(ctx, k8s.ConfigConfigMapName, metav1.GetOptions{})
if err != nil {
return nil, err
}
// for non-primitive types set only if they are not nil
if configs.GetGlobal().GetIdentityContext().GetIssuanceLifetime() != nil {
values.Identity.Issuer.IssuanceLifetime = configs.GetGlobal().GetIdentityContext().GetIssuanceLifetime().String()
}
if configs.GetGlobal().GetIdentityContext().GetClockSkewAllowance() != nil {
values.Identity.Issuer.ClockSkewAllowance = configs.GetGlobal().GetIdentityContext().GetClockSkewAllowance().String()
}
if configs.GetProxy().GetLogLevel() != nil {
values.Proxy.LogLevel = configs.GetProxy().GetLogLevel().String()
}
// set HA, and Heartbeat flags as health-check needs them for old config installs
for _, flag := range configs.GetInstall().GetFlags() {
if flag.GetName() == "ha" && flag.GetValue() == "true" {
values.HighAvailability = true
}
if flag.GetName() == "disable-heartbeat" && flag.GetValue() == "true" {
values.DisableHeartBeat = true
}
}
return values
}
func toString(portRanges []*pb.PortRange) string {
var portRangeString string
if len(portRanges) > 0 {
for i := 0; i < len(portRanges)-1; i++ {
portRangeString += portRanges[i].GetPortRange() + ","
}
portRangeString += portRanges[len(portRanges)-1].GetPortRange()
}
return portRangeString
return cm, nil
}

View File

@ -13,7 +13,6 @@ import (
"strings"
"time"
configPb "github.com/linkerd/linkerd2/controller/gen/config"
controllerK8s "github.com/linkerd/linkerd2/controller/k8s"
l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
"github.com/linkerd/linkerd2/pkg/config"
@ -1689,35 +1688,30 @@ func (hc *HealthChecker) checkCertificatesConfig(ctx context.Context) (*tls.Cred
// FetchCurrentConfiguration retrieves the current Linkerd configuration
func FetchCurrentConfiguration(ctx context.Context, k kubernetes.Interface, controlPlaneNamespace string) (*corev1.ConfigMap, *l5dcharts.Values, error) {
// Get the linkerd-config values if present
configMap, configPb, err := FetchLinkerdConfigMap(ctx, k, controlPlaneNamespace)
// Get the linkerd-config values if present.
configMap, err := config.FetchLinkerdConfigMap(ctx, k, controlPlaneNamespace)
if err != nil {
return nil, nil, err
}
if rawValues := configMap.Data["values"]; rawValues != "" {
// Convert into latest values, where global field is removed
rawValuesBytes, err := config.RemoveGlobalFieldIfPresent([]byte(rawValues))
if err != nil {
return nil, nil, err
}
rawValues = string(rawValuesBytes)
var fullValues l5dcharts.Values
err = yaml.Unmarshal([]byte(rawValues), &fullValues)
if err != nil {
return nil, nil, err
}
return configMap, &fullValues, nil
}
if configPb == nil {
rawValues := configMap.Data["values"]
if rawValues == "" {
return configMap, nil, nil
}
// fall back to the older configMap
// TODO: remove this once the newer config override secret becomes the default i.e 2.10
return configMap, config.ToValues(configPb), nil
// Convert into latest values, where global field is removed.
rawValuesBytes, err := config.RemoveGlobalFieldIfPresent([]byte(rawValues))
if err != nil {
return nil, nil, err
}
rawValues = string(rawValuesBytes)
var fullValues l5dcharts.Values
err = yaml.Unmarshal([]byte(rawValues), &fullValues)
if err != nil {
return nil, nil, err
}
return configMap, &fullValues, nil
}
func (hc *HealthChecker) fetchProxyInjectorCaBundle(ctx context.Context) ([]*x509.Certificate, error) {
@ -1802,26 +1796,6 @@ func (hc *HealthChecker) FetchCredsFromOldSecret(ctx context.Context, namespace
return cred, nil
}
// FetchLinkerdConfigMap retrieves the `linkerd-config` ConfigMap from
// Kubernetes and parses it into `linkerd2.config` protobuf.
// TODO: Consider a different package for this function. This lives in the
// healthcheck package because healthcheck depends on it, along with other
// packages that also depend on healthcheck. This function depends on both
// `pkg/k8s` and `pkg/config`, which do not depend on each other.
func FetchLinkerdConfigMap(ctx context.Context, k kubernetes.Interface, controlPlaneNamespace string) (*corev1.ConfigMap, *configPb.All, error) {
cm, err := k.CoreV1().ConfigMaps(controlPlaneNamespace).Get(ctx, k8s.ConfigConfigMapName, metav1.GetOptions{})
if err != nil {
return nil, nil, err
}
configPB, err := config.FromConfigMap(cm.Data)
if err != nil {
return nil, nil, err
}
return cm, configPB, nil
}
// CheckNamespace checks whether the given namespace exists, and returns an
// error if it does not match `shouldExist`.
func (hc *HealthChecker) CheckNamespace(ctx context.Context, namespace string, shouldExist bool) error {

View File

@ -11,19 +11,14 @@ import (
"testing"
"time"
"github.com/golang/protobuf/ptypes/duration"
configPb "github.com/linkerd/linkerd2/controller/gen/config"
"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
"github.com/linkerd/linkerd2/pkg/identity"
"github.com/linkerd/linkerd2/pkg/issuercerts"
"github.com/linkerd/linkerd2/pkg/k8s"
"github.com/linkerd/linkerd2/pkg/tls"
"github.com/linkerd/linkerd2/testutil"
"google.golang.org/protobuf/proto"
corev1 "k8s.io/api/core/v1"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type observer struct {
@ -1279,8 +1274,9 @@ apiVersion: v1
metadata:
name: %s
data:
global: |
{"identityContext":{"trustAnchorsPem": "%s"}}
values: |
identityTrustAnchorsPEM: %s
`, k8s.ConfigConfigMapName, currentCertificate)
var testCases = []struct {
@ -2170,138 +2166,6 @@ func TestKubeSystemNamespaceInHA(t *testing.T) {
}
func TestFetchLinkerdConfigMap(t *testing.T) {
testCases := []struct {
k8sConfigs []string
expected *configPb.All
err error
}{
{
[]string{`
kind: ConfigMap
apiVersion: v1
metadata:
name: linkerd-config
namespace: linkerd
data:
global: |
{"linkerdNamespace":"linkerd","cniEnabled":false,"version":"install-control-plane-version","identityContext":{"trustDomain":"cluster.local","trustAnchorsPem":"fake-trust-anchors-pem","issuanceLifetime":"86400s","clockSkewAllowance":"20s"}}
proxy: |
{"proxyImage":{"imageName":"cr.l5d.io/linkerd/proxy","pullPolicy":"IfNotPresent"},"proxyInitImage":{"imageName":"cr.l5d.io/linkerd/proxy-init","pullPolicy":"IfNotPresent"},"controlPort":{"port":4190},"ignoreInboundPorts":[],"ignoreOutboundPorts":[],"inboundPort":{"port":4143},"adminPort":{"port":4191},"outboundPort":{"port":4140},"resource":{"requestCpu":"","requestMemory":"","limitCpu":"","limitMemory":""},"proxyUid":"2102","logLevel":{"level":"warn,linkerd=info"},"disableExternalProfiles":true,"proxyVersion":"install-proxy-version","proxy_init_image_version":"v1.5.1","debugImage":{"imageName":"cr.l5d.io/linkerd/debug","pullPolicy":"IfNotPresent"},"debugImageVersion":"install-debug-version"}
install: |
{"cliVersion":"dev-undefined","flags":[]}`,
},
&configPb.All{
Global: &configPb.Global{
LinkerdNamespace: "linkerd",
Version: "install-control-plane-version",
IdentityContext: &configPb.IdentityContext{
TrustDomain: "cluster.local",
TrustAnchorsPem: "fake-trust-anchors-pem",
IssuanceLifetime: &duration.Duration{
Seconds: 86400,
},
ClockSkewAllowance: &duration.Duration{
Seconds: 20,
},
},
}, Proxy: &configPb.Proxy{
ProxyImage: &configPb.Image{
ImageName: "cr.l5d.io/linkerd/proxy",
PullPolicy: "IfNotPresent",
},
ProxyInitImage: &configPb.Image{
ImageName: "cr.l5d.io/linkerd/proxy-init",
PullPolicy: "IfNotPresent",
},
ControlPort: &configPb.Port{
Port: 4190,
},
InboundPort: &configPb.Port{
Port: 4143,
},
AdminPort: &configPb.Port{
Port: 4191,
},
OutboundPort: &configPb.Port{
Port: 4140,
},
Resource: &configPb.ResourceRequirements{},
ProxyUid: 2102,
LogLevel: &configPb.LogLevel{
Level: "warn,linkerd=info",
},
DisableExternalProfiles: true,
ProxyVersion: "install-proxy-version",
ProxyInitImageVersion: "v1.5.1",
DebugImage: &configPb.Image{
ImageName: "cr.l5d.io/linkerd/debug",
PullPolicy: "IfNotPresent",
},
DebugImageVersion: "install-debug-version",
}, Install: &configPb.Install{
CliVersion: "dev-undefined",
}},
nil,
},
{
[]string{`
kind: ConfigMap
apiVersion: v1
metadata:
name: linkerd-config
namespace: linkerd
data:
global: |
{"linkerdNamespace":"ns","identityContext":null}
proxy: "{}"
install: "{}"`,
},
&configPb.All{Global: &configPb.Global{LinkerdNamespace: "ns", IdentityContext: nil}, Proxy: &configPb.Proxy{}, Install: &configPb.Install{}},
nil,
},
{
[]string{`
kind: ConfigMap
apiVersion: v1
metadata:
name: linkerd-config
namespace: linkerd
data:
global: "{}"
proxy: "{}"
install: "{}"`,
},
&configPb.All{Global: &configPb.Global{}, Proxy: &configPb.Proxy{}, Install: &configPb.Install{}},
nil,
},
{
nil,
nil,
k8sErrors.NewNotFound(schema.GroupResource{Resource: "configmaps"}, "linkerd-config"),
},
}
for i, tc := range testCases {
tc := tc // pin
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
clientset, err := k8s.NewFakeAPI(tc.k8sConfigs...)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
_, configs, err := FetchLinkerdConfigMap(context.Background(), clientset, "linkerd")
if !reflect.DeepEqual(err, tc.err) {
t.Fatalf("Expected \"%+v\", got \"%+v\"", tc.err, err)
}
if !proto.Equal(configs, tc.expected) {
t.Fatalf("Unexpected config:\nExpected:\n%+v\nGot:\n%+v", tc.expected, configs)
}
})
}
}
func TestFetchCurrentConfiguration(t *testing.T) {
defaultValues, err := linkerd2.NewValues()
@ -2635,50 +2499,6 @@ data:
},
nil,
},
{
[]string{`
kind: ConfigMap
apiVersion: v1
metadata:
name: linkerd-config
namespace: linkerd
data:
global: |
{"linkerdNamespace":"ns","identityContext":null, "cniEnabled": true}
proxy: |
{"proxyImage":{"imageName":"registry", "pullPolicy":"Always"}}
install: |
{"flags":[{"name":"ha","value":"true"}]}`,
},
&linkerd2.Values{
Namespace: "ns",
CNIEnabled: true,
HighAvailability: true,
Proxy: &linkerd2.Proxy{
EnableExternalProfiles: true,
Image: &linkerd2.Image{
Name: "registry",
PullPolicy: "Always",
},
LogLevel: "",
Ports: &linkerd2.Ports{},
Resources: &linkerd2.Resources{
CPU: linkerd2.Constraints{},
Memory: linkerd2.Constraints{},
},
},
ProxyInit: &linkerd2.ProxyInit{
Image: &linkerd2.Image{},
},
Identity: &linkerd2.Identity{
Issuer: &linkerd2.Issuer{},
},
DebugContainer: &linkerd2.DebugContainer{
Image: &linkerd2.Image{},
},
},
nil,
},
}
for i, tc := range testCases {
@ -2710,8 +2530,13 @@ metadata:
name: linkerd-config
namespace: linkerd
data:
global: |
{"linkerdNamespace": "linkerd", "identityContext":{"trustAnchorsPem": %s, "trustDomain": "cluster.local", "scheme": "%s"}}
values: |
namespace: linkerd
identityTrustAnchorsPEM: %s
identityTrustDomain: cluster.local
identity:
issuer:
scheme: %s
---
`, anchors, scheme)
}

View File

@ -4,13 +4,15 @@ import (
"context"
"fmt"
"github.com/linkerd/linkerd2/pkg/config"
"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
"github.com/linkerd/linkerd2/pkg/k8s"
)
// GetServerVersion returns Linkerd's version, as set in linkerd-config
func GetServerVersion(ctx context.Context, controlPlaneNamespace string, kubeAPI *k8s.KubernetesAPI) (string, error) {
cm, _, err := FetchLinkerdConfigMap(ctx, kubeAPI, controlPlaneNamespace)
cm, err := config.FetchLinkerdConfigMap(ctx, kubeAPI, controlPlaneNamespace)
if err != nil {
return "", fmt.Errorf("failed to fetch linkerd-config: %s", err)
}

View File

@ -5,7 +5,6 @@ import (
"strings"
"github.com/linkerd/linkerd2-proxy-init/ports"
"github.com/linkerd/linkerd2/controller/gen/config"
log "github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
)
@ -16,8 +15,7 @@ func ParsePorts(portsString string) (map[uint32]struct{}, error) {
opaquePorts := make(map[uint32]struct{})
if portsString != "" {
portRanges := GetPortRanges(portsString)
for _, portRange := range portRanges {
pr := portRange.GetPortRange()
for _, pr := range portRanges {
portsRange, err := ports.ParsePortRange(pr)
if err != nil {
log.Warnf("Invalid port range [%v]: %s", pr, err)
@ -38,8 +36,7 @@ func ParsePorts(portsString string) (map[uint32]struct{}, error) {
func ParseContainerOpaquePorts(override string, containers []corev1.Container) []string {
portRanges := GetPortRanges(override)
var values []string
for _, portRange := range portRanges {
pr := portRange.GetPortRange()
for _, pr := range portRanges {
port, named := isNamed(pr, containers)
if named {
values = append(values, strconv.Itoa(int(port)))
@ -58,13 +55,8 @@ func ParseContainerOpaquePorts(override string, containers []corev1.Container) [
}
// GetPortRanges gets port ranges from an override annotation
func GetPortRanges(override string) []*config.PortRange {
split := strings.Split(strings.TrimSuffix(override, ","), ",")
ports := make([]*config.PortRange, len(split))
for i, p := range split {
ports[i] = &config.PortRange{PortRange: p}
}
return ports
func GetPortRanges(override string) []string {
return strings.Split(strings.TrimSuffix(override, ","), ",")
}
// isNamed checks if a port range is actually a container named port (e.g.

View File

@ -1,119 +0,0 @@
syntax = "proto3";
package linkerd2.config;
import "google/protobuf/duration.proto";
option go_package = "github.com/linkerd/linkerd2/controller/gen/config";
message All {
Global global = 1;
Proxy proxy = 2;
Install install = 3;
}
message Global {
string linkerd_namespace = 1;
bool cni_enabled = 2;
// Control plane version
string version = 3;
// If present, configures identity.
IdentityContext identity_context = 4;
AutoInjectContext auto_inject_context = 6 [deprecated=true];
bool omitWebhookSideEffects = 7 [deprecated=true];
// Override default `cluster.local`
string cluster_domain = 8;
}
message Proxy {
Image proxy_image = 1;
Image proxy_init_image = 2;
Port control_port = 3;
repeated PortRange ignore_inbound_ports = 4;
repeated PortRange ignore_outbound_ports = 5;
Port inbound_port = 6;
Port admin_port = 7;
Port outbound_port = 8;
ResourceRequirements resource = 9;
int64 proxy_uid = 10;
LogLevel log_level = 11;
bool disable_external_profiles = 12;
string proxy_version = 13;
string proxy_init_image_version = 14;
Image debug_image = 15;
string debug_image_version = 16;
string destination_get_networks = 17;
string log_format = 18;
string outbound_connect_timeout = 19;
string inbound_connect_timeout = 20;
}
message Image {
string image_name = 1;
string pull_policy = 2;
}
message Port {
uint32 port = 1;
}
message PortRange {
string port_range = 1;
}
message ResourceRequirements {
string request_cpu = 1;
string request_memory = 2;
string limit_cpu = 3;
string limit_memory = 4;
}
message AutoInjectContext { option deprecated = true; }
message IdentityContext {
string trust_domain = 1;
string trust_anchors_pem = 2;
google.protobuf.Duration issuance_lifetime = 3;
google.protobuf.Duration clock_skew_allowance = 4;
string scheme = 5;
}
message LogLevel {
string level = 1;
}
// Stores information about the last installation/upgrade.
//
// Useful for driving upgrades.
message Install {
reserved 1;
//string uuid = 1;
// The CLI version that drove the last install or upgrade.
string cli_version = 2;
// The CLI arguments to the install (or upgrade) command, indicating the
// installer's intent.
repeated Flag flags = 3;
message Flag {
string name = 1;
string value = 2;
}
}

View File

@ -10,6 +10,8 @@ import (
"syscall"
"time"
"github.com/linkerd/linkerd2/pkg/config"
"github.com/linkerd/linkerd2/pkg/admin"
"github.com/linkerd/linkerd2/pkg/charts/linkerd2"
"github.com/linkerd/linkerd2/pkg/flags"
@ -120,7 +122,7 @@ func getUUIDAndVersion(ctx context.Context, k8sAPI *k8s.KubernetesAPI, controlle
var uuid string
var version string
cm, _, err := healthcheck.FetchLinkerdConfigMap(ctx, k8sAPI, controllerNamespace)
cm, err := config.FetchLinkerdConfigMap(ctx, k8sAPI, controllerNamespace)
if err != nil {
log.Errorf("Failed to fetch linkerd-config: %s", err)
} else {