Allow multiple Pinnipeds to work on same cluster

Yes, this is a huge commit.

The middleware allows you to customize the API groups of all of the
*.pinniped.dev API groups.

Some notes about other small things in this commit:
- We removed the internal/client package in favor of pkg/conciergeclient. The
  two packages do basically the same thing. I don't think we use the former
  anymore.
- We re-enabled cluster-scoped owner assertions in the integration tests.
  This code was added in internal/ownerref. See a0546942 for when this
  assertion was removed.
- Note: the middlware code is in charge of restoring the GV of a request object,
  so we should never need to write mutations that do that.
- We updated the supervisor secret generation to no longer manually set an owner
  reference to the deployment since the middleware code now does this. I think we
  still need some way to make an initial event for the secret generator
  controller, which involves knowing the namespace and the name of the generated
  secret, so I still wired the deployment through. We could use a namespace/name
  tuple here, but I was lazy.

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
Co-authored-by: Ryan Richard <richardry@vmware.com>
This commit is contained in:
Monis Khan
2021-02-02 15:18:41 -08:00
committed by Ryan Richard
co-authored by Ryan Richard
parent 93d25a349f
commit efe1fa89fe
67 changed files with 4285 additions and 820 deletions
+6 -32
View File
@@ -10,43 +10,14 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/client-go/pkg/version"
loginapi "go.pinniped.dev/generated/1.20/apis/concierge/login"
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/registry/credentialrequest"
)
var (
//nolint: gochecknoglobals
scheme = runtime.NewScheme()
//nolint: gochecknoglobals, golint
Codecs = serializer.NewCodecFactory(scheme)
)
//nolint: gochecknoinits
func init() {
utilruntime.Must(loginv1alpha1.AddToScheme(scheme))
utilruntime.Must(loginapi.AddToScheme(scheme))
// add the options to empty v1
metav1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
unversioned := schema.GroupVersion{Group: "", Version: "v1"}
scheme.AddUnversionedTypes(unversioned,
&metav1.Status{},
&metav1.APIVersions{},
&metav1.APIGroupList{},
&metav1.APIGroup{},
&metav1.APIResourceList{},
)
}
type Config struct {
GenericConfig *genericapiserver.RecommendedConfig
ExtraConfig ExtraConfig
@@ -56,6 +27,9 @@ type ExtraConfig struct {
Authenticator credentialrequest.TokenCredentialRequestAuthenticator
Issuer credentialrequest.CertIssuer
StartControllersPostStartHook func(ctx context.Context)
Scheme *runtime.Scheme
NegotiatedSerializer runtime.NegotiatedSerializer
GroupVersion schema.GroupVersion
}
type PinnipedServer struct {
@@ -96,15 +70,15 @@ func (c completedConfig) New() (*PinnipedServer, error) {
GenericAPIServer: genericServer,
}
gvr := loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")
gvr := c.ExtraConfig.GroupVersion.WithResource("tokencredentialrequests")
storage := credentialrequest.NewREST(c.ExtraConfig.Authenticator, c.ExtraConfig.Issuer)
if err := s.GenericAPIServer.InstallAPIGroup(&genericapiserver.APIGroupInfo{
PrioritizedVersions: []schema.GroupVersion{gvr.GroupVersion()},
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{gvr.Version: {gvr.Resource: storage}},
OptionsExternalVersion: &schema.GroupVersion{Version: "v1"},
Scheme: scheme,
Scheme: c.ExtraConfig.Scheme,
ParameterCodec: metav1.ParameterCodec,
NegotiatedSerializer: Codecs,
NegotiatedSerializer: c.ExtraConfig.NegotiatedSerializer,
}); err != nil {
return nil, fmt.Errorf("could not install API group %s: %w", gvr.String(), err)
}
+72 -7
View File
@@ -11,11 +11,16 @@ import (
"time"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
genericapiserver "k8s.io/apiserver/pkg/server"
genericoptions "k8s.io/apiserver/pkg/server/options"
loginapi "go.pinniped.dev/generated/1.20/apis/concierge/login"
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/concierge/apiserver"
"go.pinniped.dev/internal/config/concierge"
@@ -23,6 +28,7 @@ import (
"go.pinniped.dev/internal/controllermanager"
"go.pinniped.dev/internal/downward"
"go.pinniped.dev/internal/dynamiccert"
"go.pinniped.dev/internal/groupsuffix"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/registry/credentialrequest"
@@ -168,24 +174,80 @@ func getAggregatedAPIServerConfig(
startControllersPostStartHook func(context.Context),
apiGroupSuffix string,
) (*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)
apiGroup, ok := groupsuffix.Replace(loginv1alpha1.GroupName, apiGroupSuffix)
if !ok {
return nil, fmt.Errorf("cannot make api group from %s/%s", loginv1alpha1.GroupName, apiGroupSuffix)
}
// standard set up of the server side scheme
scheme := runtime.NewScheme()
codecs := serializer.NewCodecFactory(scheme)
utilruntime.Must(loginv1alpha1.AddToScheme(scheme))
utilruntime.Must(loginapi.AddToScheme(scheme))
// add the options to empty v1
metav1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
unversioned := schema.GroupVersion{Group: "", Version: "v1"}
scheme.AddUnversionedTypes(unversioned,
&metav1.Status{},
&metav1.APIVersions{},
&metav1.APIGroupList{},
&metav1.APIGroup{},
&metav1.APIResourceList{},
)
// use closure to avoid mutating scheme during iteration
var addPinnipedTypeToAPIGroup []func() //nolint: prealloc // expected slice size is unknown
for gvk := range scheme.AllKnownTypes() {
gvk := gvk
if apiGroup == loginv1alpha1.GroupName {
break // bail out early if using the standard group
}
if gvk.Group != loginv1alpha1.GroupName {
continue // ignore types that are not in the aggregated API group
}
// re-register the existing type but with the new group
f := func() {
obj, err := scheme.New(gvk)
if err != nil {
panic(err) // programmer error, scheme internal code is broken
}
newGVK := schema.GroupVersionKind{
Group: apiGroup,
Version: gvk.Version,
Kind: gvk.Kind,
}
scheme.AddKnownTypeWithName(newGVK, obj)
}
addPinnipedTypeToAPIGroup = append(addPinnipedTypeToAPIGroup, f)
}
// run the closures to mutate the scheme to understand the types at the new group
for _, f := range addPinnipedTypeToAPIGroup {
f()
}
defaultEtcdPathPrefix := fmt.Sprintf("/registry/%s", apiGroup)
groupVersion := schema.GroupVersion{
Group: apiGroup,
Version: loginv1alpha1.SchemeGroupVersion.Version,
}
recommendedOptions := genericoptions.NewRecommendedOptions(
defaultEtcdPathPrefix,
apiserver.Codecs.LegacyCodec(loginv1alpha1.SchemeGroupVersion),
// TODO we should check to see if all the other default settings are acceptable for us
codecs.LegacyCodec(groupVersion),
)
recommendedOptions.Etcd = nil // turn off etcd storage because we don't need it yet
recommendedOptions.SecureServing.ServerCert.GeneratedCert = dynamicCertProvider
recommendedOptions.SecureServing.BindPort = 8443 // Don't run on default 443 because that requires root
serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs)
serverConfig := genericapiserver.NewRecommendedConfig(codecs)
// Note that among other things, this ApplyTo() function copies
// `recommendedOptions.SecureServing.ServerCert.GeneratedCert` into
// `serverConfig.SecureServing.Cert` thus making `dynamicCertProvider`
@@ -205,6 +267,9 @@ func getAggregatedAPIServerConfig(
Authenticator: authenticator,
Issuer: issuer,
StartControllersPostStartHook: startControllersPostStartHook,
Scheme: scheme,
NegotiatedSerializer: codecs,
GroupVersion: groupVersion,
},
}
return apiServerConfig, nil