internal/config: wire API group suffix through to server components

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
This commit is contained in:
Andrew Keesler 2021-01-19 10:52:12 -05:00
parent 616211c1bc
commit 88fd9e5c5e
No known key found for this signature in database
GPG Key ID: 27CE0444346F9413
11 changed files with 127 additions and 15 deletions

View File

@ -264,6 +264,7 @@ func run(podInfo *downward.PodInfo, cfg *supervisor.Config) error {
return fmt.Errorf("cannot create deployment ref: %w", err) return fmt.Errorf("cannot create deployment ref: %w", err)
} }
_ = *cfg.APIGroupSuffix // TODO: wire API group into kubeclient.
client, err := kubeclient.New(dref) client, err := kubeclient.New(dref)
if err != nil { if err != nil {
return fmt.Errorf("cannot create k8s client: %w", err) return fmt.Errorf("cannot create k8s client: %w", err)

View File

@ -0,0 +1,29 @@
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package apigroup provides centralized logic around Pinniped's API group parameterization.
package apigroup
import (
"fmt"
"strings"
)
// defaultAPIGroupSuffix is the default suffix of the Concierge API group. Our generated code uses
// this suffix, so we know that we can replace this suffix with the configured API group suffix.
const defaultAPIGroupSuffix = "pinniped.dev"
// Make constructs an API group from a baseAPIGroup and a parameterized apiGroupSuffix.
//
// We assume that all apiGroup's will end in "pinniped.dev", and therefore we can safely replace the
// reference to "pinniped.dev" with the provided apiGroupSuffix. If the provided baseAPIGroup does
// not end in "pinniped.dev", then this function will return an empty string and false.
//
// See Example_loginv1alpha1 and Example_string for more information on input/output pairs.
func Make(baseAPIGroup, apiGroupSuffix string) (string, bool) {
if !strings.HasSuffix(baseAPIGroup, defaultAPIGroupSuffix) {
return "", false
}
i := strings.LastIndex(baseAPIGroup, defaultAPIGroupSuffix)
return fmt.Sprintf("%s%s", baseAPIGroup[:i], apiGroupSuffix), true
}

View File

@ -0,0 +1,36 @@
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package apigroup
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
)
func TestMakeError(t *testing.T) {
_, ok := Make("bad-suffix", "shouldnt-matter.com")
require.False(t, ok)
}
func TestMakeSuffix(t *testing.T) {
s, ok := Make("something.pinniped.dev.something-else.pinniped.dev", "tuna.io")
require.Equal(t, "something.pinniped.dev.something-else.tuna.io", s)
require.True(t, ok)
}
func Example_loginv1alpha1() {
s, _ := Make(loginv1alpha1.GroupName, "tuna.fish.io")
fmt.Println(s)
// Output: login.concierge.tuna.fish.io
}
func Example_string() {
s, _ := Make("idp.supervisor.pinniped.dev", "marlin.io")
fmt.Println(s)
// Output: idp.supervisor.marlin.io
}

View File

@ -15,6 +15,7 @@ import (
genericoptions "k8s.io/apiserver/pkg/server/options" genericoptions "k8s.io/apiserver/pkg/server/options"
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1" loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
"go.pinniped.dev/internal/apigroup"
"go.pinniped.dev/internal/certauthority/dynamiccertauthority" "go.pinniped.dev/internal/certauthority/dynamiccertauthority"
"go.pinniped.dev/internal/concierge/apiserver" "go.pinniped.dev/internal/concierge/apiserver"
"go.pinniped.dev/internal/config/concierge" "go.pinniped.dev/internal/config/concierge"
@ -36,10 +37,6 @@ type App struct {
downwardAPIPath string downwardAPIPath string
} }
// This is ignored for now because we turn off etcd storage below, but this is
// the right prefix in case we turn it back on.
const defaultEtcdPathPrefix = "/registry/" + loginv1alpha1.GroupName
// New constructs a new App with command line args, stdout and stderr. // New constructs a new App with command line args, stdout and stderr.
func New(ctx context.Context, args []string, stdout, stderr io.Writer) *App { func New(ctx context.Context, args []string, stdout, stderr io.Writer) *App {
app := &App{} app := &App{}
@ -125,6 +122,7 @@ func (a *App) runServer(ctx context.Context) error {
startControllersFunc, err := controllermanager.PrepareControllers( startControllersFunc, err := controllermanager.PrepareControllers(
&controllermanager.Config{ &controllermanager.Config{
ServerInstallationInfo: podInfo, ServerInstallationInfo: podInfo,
APIGroupSuffix: *cfg.APIGroupSuffix,
NamesConfig: &cfg.NamesConfig, NamesConfig: &cfg.NamesConfig,
Labels: cfg.Labels, Labels: cfg.Labels,
KubeCertAgentConfig: &cfg.KubeCertAgentConfig, KubeCertAgentConfig: &cfg.KubeCertAgentConfig,
@ -146,6 +144,7 @@ func (a *App) runServer(ctx context.Context) error {
authenticators, authenticators,
dynamiccertauthority.New(dynamicSigningCertProvider), dynamiccertauthority.New(dynamicSigningCertProvider),
startControllersFunc, startControllersFunc,
*cfg.APIGroupSuffix,
) )
if err != nil { if err != nil {
return fmt.Errorf("could not configure aggregated API server: %w", err) return fmt.Errorf("could not configure aggregated API server: %w", err)
@ -167,7 +166,16 @@ func getAggregatedAPIServerConfig(
authenticator credentialrequest.TokenCredentialRequestAuthenticator, authenticator credentialrequest.TokenCredentialRequestAuthenticator,
issuer credentialrequest.CertIssuer, issuer credentialrequest.CertIssuer,
startControllersPostStartHook func(context.Context), startControllersPostStartHook func(context.Context),
apiGroupSuffix string,
) (*apiserver.Config, error) { ) (*apiserver.Config, error) {
// This is ignored for now because we turn off etcd storage below, but this is
// the right prefix in case we turn it back on.
apiGroup, ok := apigroup.Make(loginv1alpha1.GroupName, apiGroupSuffix)
if !ok {
return nil, fmt.Errorf("cannot make api group from %s/%s", loginv1alpha1.GroupName, apiGroupSuffix)
}
defaultEtcdPathPrefix := fmt.Sprintf("/registry/%s", apiGroup)
recommendedOptions := genericoptions.NewRecommendedOptions( recommendedOptions := genericoptions.NewRecommendedOptions(
defaultEtcdPathPrefix, defaultEtcdPathPrefix,
apiserver.Codecs.LegacyCodec(loginv1alpha1.SchemeGroupVersion), apiserver.Codecs.LegacyCodec(loginv1alpha1.SchemeGroupVersion),

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package concierge contains functionality to load/store Config's from/to // Package concierge contains functionality to load/store Config's from/to
@ -40,6 +40,7 @@ func FromPath(path string) (*Config, error) {
} }
maybeSetAPIDefaults(&config.APIConfig) maybeSetAPIDefaults(&config.APIConfig)
maybeSetAPIGroupSuffixDefault(&config.APIGroupSuffix)
maybeSetKubeCertAgentDefaults(&config.KubeCertAgentConfig) maybeSetKubeCertAgentDefaults(&config.KubeCertAgentConfig)
if err := validateAPI(&config.APIConfig); err != nil { if err := validateAPI(&config.APIConfig); err != nil {
@ -71,6 +72,12 @@ func maybeSetAPIDefaults(apiConfig *APIConfigSpec) {
} }
} }
func maybeSetAPIGroupSuffixDefault(apiGroupSuffix **string) {
if *apiGroupSuffix == nil {
*apiGroupSuffix = stringPtr("pinniped.dev")
}
}
func maybeSetKubeCertAgentDefaults(cfg *KubeCertAgentSpec) { func maybeSetKubeCertAgentDefaults(cfg *KubeCertAgentSpec) {
if cfg.NamePrefix == nil { if cfg.NamePrefix == nil {
cfg.NamePrefix = stringPtr("pinniped-kube-cert-agent-") cfg.NamePrefix = stringPtr("pinniped-kube-cert-agent-")

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package concierge package concierge
@ -30,6 +30,7 @@ func TestFromPath(t *testing.T) {
servingCertificate: servingCertificate:
durationSeconds: 3600 durationSeconds: 3600
renewBeforeSeconds: 2400 renewBeforeSeconds: 2400
apiGroupSuffix: some.suffix.com
names: names:
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
credentialIssuer: pinniped-config credentialIssuer: pinniped-config
@ -53,6 +54,7 @@ func TestFromPath(t *testing.T) {
RenewBeforeSeconds: int64Ptr(2400), RenewBeforeSeconds: int64Ptr(2400),
}, },
}, },
APIGroupSuffix: stringPtr("some.suffix.com"),
NamesConfig: NamesConfigSpec{ NamesConfig: NamesConfigSpec{
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate", ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
CredentialIssuer: "pinniped-config", CredentialIssuer: "pinniped-config",
@ -82,6 +84,7 @@ func TestFromPath(t *testing.T) {
DiscoveryInfo: DiscoveryInfoSpec{ DiscoveryInfo: DiscoveryInfoSpec{
URL: nil, URL: nil,
}, },
APIGroupSuffix: stringPtr("pinniped.dev"),
APIConfig: APIConfigSpec{ APIConfig: APIConfigSpec{
ServingCertificateConfig: ServingCertificateConfigSpec{ ServingCertificateConfig: ServingCertificateConfigSpec{
DurationSeconds: int64Ptr(60 * 60 * 24 * 365), // about a year DurationSeconds: int64Ptr(60 * 60 * 24 * 365), // about a year

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package concierge package concierge
@ -9,6 +9,7 @@ import "go.pinniped.dev/internal/plog"
type Config struct { type Config struct {
DiscoveryInfo DiscoveryInfoSpec `json:"discovery"` DiscoveryInfo DiscoveryInfoSpec `json:"discovery"`
APIConfig APIConfigSpec `json:"api"` APIConfig APIConfigSpec `json:"api"`
APIGroupSuffix *string `json:"apiGroupSuffix,omitempty"`
NamesConfig NamesConfigSpec `json:"names"` NamesConfig NamesConfigSpec `json:"names"`
KubeCertAgentConfig KubeCertAgentSpec `json:"kubeCertAgent"` KubeCertAgentConfig KubeCertAgentSpec `json:"kubeCertAgent"`
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package supervisor contains functionality to load/store Config's from/to // Package supervisor contains functionality to load/store Config's from/to
@ -34,6 +34,8 @@ func FromPath(path string) (*Config, error) {
config.Labels = make(map[string]string) config.Labels = make(map[string]string)
} }
maybeSetAPIGroupSuffixDefault(&config.APIGroupSuffix)
if err := validateNames(&config.NamesConfig); err != nil { if err := validateNames(&config.NamesConfig); err != nil {
return nil, fmt.Errorf("validate names: %w", err) return nil, fmt.Errorf("validate names: %w", err)
} }
@ -45,6 +47,12 @@ func FromPath(path string) (*Config, error) {
return &config, nil return &config, nil
} }
func maybeSetAPIGroupSuffixDefault(apiGroupSuffix **string) {
if *apiGroupSuffix == nil {
*apiGroupSuffix = stringPtr("pinniped.dev")
}
}
func validateNames(names *NamesConfigSpec) error { func validateNames(names *NamesConfigSpec) error {
missingNames := []string{} missingNames := []string{}
if names.DefaultTLSCertificateSecret == "" { if names.DefaultTLSCertificateSecret == "" {
@ -55,3 +63,7 @@ func validateNames(names *NamesConfigSpec) error {
} }
return nil return nil
} }
func stringPtr(s string) *string {
return &s
}

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package supervisor package supervisor
@ -24,6 +24,7 @@ func TestFromPath(t *testing.T) {
name: "Happy", name: "Happy",
yaml: here.Doc(` yaml: here.Doc(`
--- ---
apiGroupSuffix: some.suffix.com
labels: labels:
myLabelKey1: myLabelValue1 myLabelKey1: myLabelValue1
myLabelKey2: myLabelValue2 myLabelKey2: myLabelValue2
@ -31,6 +32,7 @@ func TestFromPath(t *testing.T) {
defaultTLSCertificateSecret: my-secret-name defaultTLSCertificateSecret: my-secret-name
`), `),
wantConfig: &Config{ wantConfig: &Config{
APIGroupSuffix: stringPtr("some.suffix.com"),
Labels: map[string]string{ Labels: map[string]string{
"myLabelKey1": "myLabelValue1", "myLabelKey1": "myLabelValue1",
"myLabelKey2": "myLabelValue2", "myLabelKey2": "myLabelValue2",
@ -48,6 +50,7 @@ func TestFromPath(t *testing.T) {
defaultTLSCertificateSecret: my-secret-name defaultTLSCertificateSecret: my-secret-name
`), `),
wantConfig: &Config{ wantConfig: &Config{
APIGroupSuffix: stringPtr("pinniped.dev"),
Labels: map[string]string{}, Labels: map[string]string{},
NamesConfig: NamesConfigSpec{ NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name", DefaultTLSCertificateSecret: "my-secret-name",

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package supervisor package supervisor
@ -7,6 +7,7 @@ import "go.pinniped.dev/internal/plog"
// Config contains knobs to setup an instance of the Pinniped Supervisor. // Config contains knobs to setup an instance of the Pinniped Supervisor.
type Config struct { type Config struct {
APIGroupSuffix *string `json:"apiGroupSuffix,omitempty"`
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`
NamesConfig NamesConfigSpec `json:"names"` NamesConfig NamesConfigSpec `json:"names"`
LogLevel plog.LogLevel `json:"logLevel"` LogLevel plog.LogLevel `json:"logLevel"`

View File

@ -18,6 +18,7 @@ import (
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1" loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
pinnipedclientset "go.pinniped.dev/generated/1.20/client/concierge/clientset/versioned" pinnipedclientset "go.pinniped.dev/generated/1.20/client/concierge/clientset/versioned"
pinnipedinformers "go.pinniped.dev/generated/1.20/client/concierge/informers/externalversions" pinnipedinformers "go.pinniped.dev/generated/1.20/client/concierge/informers/externalversions"
"go.pinniped.dev/internal/apigroup"
"go.pinniped.dev/internal/config/concierge" "go.pinniped.dev/internal/config/concierge"
"go.pinniped.dev/internal/controller/apicerts" "go.pinniped.dev/internal/controller/apicerts"
"go.pinniped.dev/internal/controller/authenticator/authncache" "go.pinniped.dev/internal/controller/authenticator/authncache"
@ -45,6 +46,9 @@ type Config struct {
// ServerInstallationInfo provides the name of the pod in which Pinniped is running and the namespace in which Pinniped is deployed. // ServerInstallationInfo provides the name of the pod in which Pinniped is running and the namespace in which Pinniped is deployed.
ServerInstallationInfo *downward.PodInfo ServerInstallationInfo *downward.PodInfo
// APIGroupSuffix is the suffix of the Pinniped API that should be targeted by these controllers.
APIGroupSuffix string
// NamesConfig comes from the Pinniped config API (see api.Config). It specifies how Kubernetes // NamesConfig comes from the Pinniped config API (see api.Config). It specifies how Kubernetes
// objects should be named. // objects should be named.
NamesConfig *concierge.NamesConfigSpec NamesConfig *concierge.NamesConfigSpec
@ -85,6 +89,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
return nil, fmt.Errorf("cannot create deployment ref: %w", err) return nil, fmt.Errorf("cannot create deployment ref: %w", err)
} }
_ = c.APIGroupSuffix // TODO: wire API group into kubeclient.
client, err := kubeclient.New(dref) client, err := kubeclient.New(dref)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not create clients for the controllers: %w", err) return nil, fmt.Errorf("could not create clients for the controllers: %w", err)
@ -106,6 +111,12 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
Name: c.NamesConfig.CredentialIssuer, Name: c.NamesConfig.CredentialIssuer,
} }
groupName, ok := apigroup.Make(loginv1alpha1.GroupName, c.APIGroupSuffix)
if !ok {
return nil, fmt.Errorf("cannot make api group from %s/%s", loginv1alpha1.GroupName, c.APIGroupSuffix)
}
apiServiceName := loginv1alpha1.SchemeGroupVersion.Version + "." + groupName
// Create controller manager. // Create controller manager.
controllerManager := controllerlib. controllerManager := controllerlib.
NewManager(). NewManager().
@ -145,7 +156,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
apicerts.NewAPIServiceUpdaterController( apicerts.NewAPIServiceUpdaterController(
c.ServerInstallationInfo.Namespace, c.ServerInstallationInfo.Namespace,
c.NamesConfig.ServingCertificateSecret, c.NamesConfig.ServingCertificateSecret,
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName, apiServiceName,
client.Aggregation, client.Aggregation,
informers.installationNamespaceK8s.Core().V1().Secrets(), informers.installationNamespaceK8s.Core().V1().Secrets(),
controllerlib.WithInformer, controllerlib.WithInformer,