2021-01-19 18:50:22 +00:00
|
|
|
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
2020-09-16 14:19:51 +00:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2020-08-01 00:37:59 +00:00
|
|
|
|
|
|
|
package integration
|
|
|
|
|
|
|
|
import (
|
2021-01-13 01:27:41 +00:00
|
|
|
"errors"
|
2021-01-19 18:50:22 +00:00
|
|
|
"fmt"
|
2020-11-12 22:24:25 +00:00
|
|
|
"strings"
|
2020-08-01 00:37:59 +00:00
|
|
|
"testing"
|
|
|
|
|
2020-11-12 22:24:25 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2020-08-01 00:37:59 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2021-01-19 18:50:22 +00:00
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2021-02-19 18:21:10 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
2021-01-13 01:27:41 +00:00
|
|
|
"k8s.io/client-go/discovery"
|
2020-08-01 00:37:59 +00:00
|
|
|
|
2020-09-18 19:56:24 +00:00
|
|
|
"go.pinniped.dev/test/library"
|
2020-08-01 00:37:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestGetAPIResourceList(t *testing.T) {
|
2021-01-19 18:50:22 +00:00
|
|
|
env := library.IntegrationEnv(t)
|
2020-08-07 01:44:14 +00:00
|
|
|
|
2021-01-13 01:27:41 +00:00
|
|
|
client := library.NewKubernetesClientset(t)
|
2020-08-01 00:37:59 +00:00
|
|
|
groups, resources, err := client.Discovery().ServerGroupsAndResources()
|
2021-01-13 01:27:41 +00:00
|
|
|
|
|
|
|
// discovery can have partial failures when an API service is unavailable (i.e. because of TestAPIServingCertificateAutoCreationAndRotation)
|
|
|
|
// we ignore failures for groups that are not relevant to this test
|
|
|
|
if err != nil {
|
|
|
|
discoveryFailed := &discovery.ErrGroupDiscoveryFailed{}
|
|
|
|
isDiscoveryFailed := errors.As(err, &discoveryFailed)
|
|
|
|
require.True(t, isDiscoveryFailed, err)
|
|
|
|
for gv, gvErr := range discoveryFailed.Groups {
|
|
|
|
if strings.HasSuffix(gv.Group, "."+env.APIGroupSuffix) {
|
|
|
|
require.NoError(t, gvErr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-01 00:37:59 +00:00
|
|
|
|
2021-01-19 18:50:22 +00:00
|
|
|
makeGV := func(firstSegment, secondSegment string) schema.GroupVersion {
|
|
|
|
return schema.GroupVersion{
|
|
|
|
Group: fmt.Sprintf("%s.%s.%s", firstSegment, secondSegment, env.APIGroupSuffix),
|
|
|
|
Version: "v1alpha1",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loginConciergeGV := makeGV("login", "concierge")
|
2021-02-19 18:21:10 +00:00
|
|
|
identityConciergeGV := makeGV("identity", "concierge")
|
2021-01-19 18:50:22 +00:00
|
|
|
authenticationConciergeGV := makeGV("authentication", "concierge")
|
|
|
|
configConciergeGV := makeGV("config", "concierge")
|
|
|
|
idpSupervisorGV := makeGV("idp", "supervisor")
|
|
|
|
configSupervisorGV := makeGV("config", "supervisor")
|
|
|
|
|
2020-09-09 15:36:38 +00:00
|
|
|
tests := []struct {
|
|
|
|
group metav1.APIGroup
|
|
|
|
resourceByVersion map[string][]metav1.APIResource
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
group: metav1.APIGroup{
|
2021-01-19 18:50:22 +00:00
|
|
|
Name: loginConciergeGV.Group,
|
2020-09-09 15:36:38 +00:00
|
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
|
|
{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: loginConciergeGV.String(),
|
|
|
|
Version: loginConciergeGV.Version,
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: loginConciergeGV.String(),
|
|
|
|
Version: loginConciergeGV.Version,
|
2020-09-09 15:23:28 +00:00
|
|
|
},
|
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
resourceByVersion: map[string][]metav1.APIResource{
|
2021-01-19 18:50:22 +00:00
|
|
|
loginConciergeGV.String(): {
|
2020-09-09 15:36:38 +00:00
|
|
|
{
|
2020-09-18 22:15:04 +00:00
|
|
|
Name: "tokencredentialrequests",
|
|
|
|
Kind: "TokenCredentialRequest",
|
2021-02-05 15:55:19 +00:00
|
|
|
Verbs: []string{"create", "list"},
|
2021-02-09 16:57:34 +00:00
|
|
|
Namespaced: false,
|
2020-11-13 18:09:22 +00:00
|
|
|
Categories: []string{"pinniped"},
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
2020-09-09 15:23:28 +00:00
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
2021-02-19 18:21:10 +00:00
|
|
|
{
|
|
|
|
group: metav1.APIGroup{
|
|
|
|
Name: identityConciergeGV.Group,
|
|
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
|
|
{
|
|
|
|
GroupVersion: identityConciergeGV.String(),
|
|
|
|
Version: identityConciergeGV.Version,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
|
|
|
GroupVersion: identityConciergeGV.String(),
|
|
|
|
Version: identityConciergeGV.Version,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
resourceByVersion: map[string][]metav1.APIResource{
|
|
|
|
identityConciergeGV.String(): {
|
|
|
|
{
|
|
|
|
Name: "whoamirequests",
|
|
|
|
Kind: "WhoAmIRequest",
|
|
|
|
Verbs: []string{"create", "list"},
|
|
|
|
Namespaced: false,
|
|
|
|
Categories: []string{"pinniped"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
{
|
|
|
|
group: metav1.APIGroup{
|
2021-01-19 18:50:22 +00:00
|
|
|
Name: configSupervisorGV.Group,
|
2020-09-09 15:36:38 +00:00
|
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
|
|
{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: configSupervisorGV.String(),
|
|
|
|
Version: configSupervisorGV.Version,
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: configSupervisorGV.String(),
|
|
|
|
Version: configSupervisorGV.Version,
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
2020-09-09 15:23:28 +00:00
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
resourceByVersion: map[string][]metav1.APIResource{
|
2021-01-19 18:50:22 +00:00
|
|
|
configSupervisorGV.String(): {
|
2020-10-07 00:53:29 +00:00
|
|
|
{
|
2020-12-16 22:27:09 +00:00
|
|
|
Name: "federationdomains",
|
|
|
|
SingularName: "federationdomain",
|
2020-10-07 00:53:29 +00:00
|
|
|
Namespaced: true,
|
2020-12-16 22:27:09 +00:00
|
|
|
Kind: "FederationDomain",
|
2020-10-07 00:53:29 +00:00
|
|
|
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
2020-11-12 22:24:25 +00:00
|
|
|
Categories: []string{"pinniped"},
|
2020-10-07 00:53:29 +00:00
|
|
|
},
|
2021-02-11 02:20:19 +00:00
|
|
|
{
|
|
|
|
Name: "federationdomains/status",
|
|
|
|
Namespaced: true,
|
|
|
|
Kind: "FederationDomain",
|
|
|
|
Verbs: []string{"get", "patch", "update"},
|
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-11-12 00:28:42 +00:00
|
|
|
{
|
|
|
|
group: metav1.APIGroup{
|
2021-01-19 18:50:22 +00:00
|
|
|
Name: idpSupervisorGV.Group,
|
2020-11-12 00:28:42 +00:00
|
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
|
|
{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: idpSupervisorGV.String(),
|
|
|
|
Version: idpSupervisorGV.Version,
|
2020-11-12 00:28:42 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: idpSupervisorGV.String(),
|
|
|
|
Version: idpSupervisorGV.Version,
|
2020-11-12 00:28:42 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
resourceByVersion: map[string][]metav1.APIResource{
|
2021-01-19 18:50:22 +00:00
|
|
|
idpSupervisorGV.String(): {
|
2020-11-12 00:28:42 +00:00
|
|
|
{
|
2020-12-16 22:27:09 +00:00
|
|
|
Name: "oidcidentityproviders",
|
|
|
|
SingularName: "oidcidentityprovider",
|
2020-11-12 00:28:42 +00:00
|
|
|
Namespaced: true,
|
2020-12-16 22:27:09 +00:00
|
|
|
Kind: "OIDCIdentityProvider",
|
2020-11-12 00:28:42 +00:00
|
|
|
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
|
|
|
Categories: []string{"pinniped", "pinniped-idp", "pinniped-idps"},
|
|
|
|
},
|
|
|
|
{
|
2020-12-16 22:27:09 +00:00
|
|
|
Name: "oidcidentityproviders/status",
|
2020-11-12 00:28:42 +00:00
|
|
|
Namespaced: true,
|
2020-12-16 22:27:09 +00:00
|
|
|
Kind: "OIDCIdentityProvider",
|
2020-11-12 00:28:42 +00:00
|
|
|
Verbs: []string{"get", "patch", "update"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-10-30 20:09:14 +00:00
|
|
|
{
|
|
|
|
group: metav1.APIGroup{
|
2021-01-19 18:50:22 +00:00
|
|
|
Name: configConciergeGV.Group,
|
2020-10-30 20:09:14 +00:00
|
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
|
|
{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: configConciergeGV.String(),
|
|
|
|
Version: configConciergeGV.Version,
|
2020-10-30 20:09:14 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: configConciergeGV.String(),
|
|
|
|
Version: configConciergeGV.Version,
|
2020-10-30 20:09:14 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
resourceByVersion: map[string][]metav1.APIResource{
|
2021-01-19 18:50:22 +00:00
|
|
|
configConciergeGV.String(): {
|
2020-10-30 20:09:14 +00:00
|
|
|
{
|
2020-11-02 21:39:43 +00:00
|
|
|
Name: "credentialissuers",
|
|
|
|
SingularName: "credentialissuer",
|
2021-02-09 16:57:34 +00:00
|
|
|
Namespaced: false,
|
2020-11-02 21:39:43 +00:00
|
|
|
Kind: "CredentialIssuer",
|
2020-10-30 20:09:14 +00:00
|
|
|
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
2020-11-12 22:24:25 +00:00
|
|
|
Categories: []string{"pinniped"},
|
2020-10-30 20:09:14 +00:00
|
|
|
},
|
2021-02-11 02:20:19 +00:00
|
|
|
{
|
|
|
|
Name: "credentialissuers/status",
|
|
|
|
Namespaced: false,
|
|
|
|
Kind: "CredentialIssuer",
|
|
|
|
Verbs: []string{"get", "patch", "update"},
|
|
|
|
},
|
2020-10-30 20:09:14 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
{
|
|
|
|
group: metav1.APIGroup{
|
2021-01-19 18:50:22 +00:00
|
|
|
Name: authenticationConciergeGV.Group,
|
2020-09-09 15:36:38 +00:00
|
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
|
|
{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: authenticationConciergeGV.String(),
|
|
|
|
Version: authenticationConciergeGV.Version,
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
2021-01-19 18:50:22 +00:00
|
|
|
GroupVersion: authenticationConciergeGV.String(),
|
|
|
|
Version: authenticationConciergeGV.Version,
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
resourceByVersion: map[string][]metav1.APIResource{
|
2021-01-19 18:50:22 +00:00
|
|
|
authenticationConciergeGV.String(): {
|
2020-09-09 15:36:38 +00:00
|
|
|
{
|
2020-10-30 16:39:26 +00:00
|
|
|
Name: "webhookauthenticators",
|
|
|
|
SingularName: "webhookauthenticator",
|
2021-02-09 16:57:34 +00:00
|
|
|
Namespaced: false,
|
2020-10-30 16:39:26 +00:00
|
|
|
Kind: "WebhookAuthenticator",
|
2020-09-09 15:36:38 +00:00
|
|
|
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
2020-11-12 22:24:25 +00:00
|
|
|
Categories: []string{"pinniped", "pinniped-authenticator", "pinniped-authenticators"},
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
2021-02-11 02:20:19 +00:00
|
|
|
{
|
|
|
|
Name: "webhookauthenticators/status",
|
|
|
|
Namespaced: false,
|
|
|
|
Kind: "WebhookAuthenticator",
|
|
|
|
Verbs: []string{"get", "patch", "update"},
|
|
|
|
},
|
2020-12-08 01:37:43 +00:00
|
|
|
{
|
|
|
|
Name: "jwtauthenticators",
|
|
|
|
SingularName: "jwtauthenticator",
|
2021-02-09 16:57:34 +00:00
|
|
|
Namespaced: false,
|
2020-12-08 01:37:43 +00:00
|
|
|
Kind: "JWTAuthenticator",
|
|
|
|
Verbs: []string{"delete", "deletecollection", "get", "list", "patch", "create", "update", "watch"},
|
|
|
|
Categories: []string{"pinniped", "pinniped-authenticator", "pinniped-authenticators"},
|
|
|
|
},
|
2021-02-11 02:20:19 +00:00
|
|
|
{
|
|
|
|
Name: "jwtauthenticators/status",
|
|
|
|
Namespaced: false,
|
|
|
|
Kind: "JWTAuthenticator",
|
|
|
|
Verbs: []string{"get", "patch", "update"},
|
|
|
|
},
|
2020-09-09 15:36:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-08-01 00:37:59 +00:00
|
|
|
}
|
2020-09-09 15:23:28 +00:00
|
|
|
|
2020-11-12 22:24:25 +00:00
|
|
|
t.Run("every Pinniped API has explicit test coverage", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testedGroups := map[string]bool{}
|
|
|
|
for _, tt := range tests {
|
|
|
|
testedGroups[tt.group.Name] = true
|
|
|
|
}
|
2021-01-13 01:27:41 +00:00
|
|
|
foundPinnipedGroups := 0
|
2020-11-12 22:24:25 +00:00
|
|
|
for _, g := range groups {
|
2021-01-19 18:50:22 +00:00
|
|
|
if !strings.Contains(g.Name, env.APIGroupSuffix) {
|
2020-11-12 22:24:25 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-01-13 01:27:41 +00:00
|
|
|
foundPinnipedGroups++
|
2020-11-12 22:24:25 +00:00
|
|
|
assert.Truef(t, testedGroups[g.Name], "expected group %q to have assertions defined", g.Name)
|
|
|
|
}
|
2021-01-13 01:27:41 +00:00
|
|
|
require.Equal(t, len(testedGroups), foundPinnipedGroups)
|
2020-11-12 22:24:25 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("every API categorized appropriately", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, r := range resources {
|
2021-01-19 18:50:22 +00:00
|
|
|
if !strings.Contains(r.GroupVersion, env.APIGroupSuffix) {
|
2020-11-12 22:24:25 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, a := range r.APIResources {
|
2020-11-12 00:28:42 +00:00
|
|
|
if strings.HasSuffix(a.Name, "/status") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
assert.Containsf(t, a.Categories, "pinniped", "expected resource %q to be in the 'pinniped' category", a.Name)
|
2020-11-13 18:09:22 +00:00
|
|
|
assert.NotContainsf(t, a.Categories, "all", "expected resource %q not to be in the 'all' category", a.Name)
|
2020-11-12 22:24:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-02-09 16:57:34 +00:00
|
|
|
t.Run("every concierge API is cluster scoped", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, r := range resources {
|
|
|
|
if !strings.Contains(r.GroupVersion, env.APIGroupSuffix) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.Contains(r.GroupVersion, ".concierge.") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, a := range r.APIResources {
|
|
|
|
assert.False(t, a.Namespaced, "concierge APIs must be cluster scoped: %#v", a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-02-11 02:20:19 +00:00
|
|
|
t.Run("every API has a status subresource", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2021-02-19 18:21:10 +00:00
|
|
|
aggregatedAPIs := sets.NewString("tokencredentialrequests", "whoamirequests")
|
|
|
|
|
2021-02-11 02:20:19 +00:00
|
|
|
var regular, status []string
|
|
|
|
|
|
|
|
for _, r := range resources {
|
|
|
|
if !strings.Contains(r.GroupVersion, env.APIGroupSuffix) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, a := range r.APIResources {
|
2021-02-19 18:21:10 +00:00
|
|
|
if aggregatedAPIs.Has(a.Name) {
|
|
|
|
continue // skip our special aggregated APIs with their own magical properties
|
2021-02-11 02:20:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasSuffix(a.Name, "/status") {
|
|
|
|
status = append(status, strings.TrimSuffix(a.Name, "/status"))
|
|
|
|
} else {
|
|
|
|
regular = append(regular, a.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, regular, status)
|
|
|
|
})
|
|
|
|
|
2020-11-12 22:49:21 +00:00
|
|
|
t.Run("Pinniped resources do not have short names", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
for _, r := range resources {
|
2021-01-19 18:50:22 +00:00
|
|
|
if !strings.Contains(r.GroupVersion, env.APIGroupSuffix) {
|
2020-11-12 22:49:21 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for _, a := range r.APIResources {
|
|
|
|
assert.Empty(t, a.ShortNames, "expected resource %q not to have any short names", a.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-09-09 15:36:38 +00:00
|
|
|
for _, tt := range tests {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.group.Name, func(t *testing.T) {
|
2020-11-12 22:24:25 +00:00
|
|
|
t.Parallel()
|
2020-09-09 15:36:38 +00:00
|
|
|
require.Contains(t, groups, &tt.group)
|
|
|
|
|
|
|
|
for groupVersion, expectedResources := range tt.resourceByVersion {
|
|
|
|
// Find the actual resource list and make a copy.
|
|
|
|
var actualResourceList *metav1.APIResourceList
|
|
|
|
for _, resource := range resources {
|
|
|
|
if resource.GroupVersion == groupVersion {
|
|
|
|
actualResourceList = resource.DeepCopy()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NotNilf(t, actualResourceList, "could not find groupVersion %s", groupVersion)
|
|
|
|
|
|
|
|
// Because its hard to predict the storage version hash (e.g. "t/+v41y+3e4="), we just don't
|
|
|
|
// worry about comparing that field.
|
|
|
|
for i := range actualResourceList.APIResources {
|
|
|
|
actualResourceList.APIResources[i].StorageVersionHash = ""
|
|
|
|
}
|
2020-10-07 18:42:30 +00:00
|
|
|
require.ElementsMatch(t, expectedResources, actualResourceList.APIResources, "unexpected API resources")
|
2020-09-09 15:36:38 +00:00
|
|
|
}
|
|
|
|
})
|
2020-09-09 15:23:28 +00:00
|
|
|
}
|
2020-08-01 00:37:59 +00:00
|
|
|
}
|