Commit aa7d9b1d authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #52950 from liggitt/persist-rbac-v1

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Change RBAC storage version to v1 for 1.9 v1 was introduced in 1.8, but storage version remained at v1beta1 to accommodate HA rolling upgrades. in 1.9, we can change the persisted and preferred version to v1 ```release-note RBAC objects are now stored in etcd in v1 format. After completing an upgrade to 1.9, RBAC objects (Roles, RoleBindings, ClusterRoles, ClusterRoleBindings) should be migrated to ensure all persisted objects are written in `v1` format, prior to `v1alpha1` support being removed in a future release. ```
parents 028ee090 232db3b8
......@@ -106,14 +106,14 @@
"description": "get information of a group"
},
{
"path": "/apis/rbac.authorization.k8s.io/v1beta1",
"description": "API at /apis/rbac.authorization.k8s.io/v1beta1"
},
{
"path": "/apis/rbac.authorization.k8s.io/v1",
"description": "API at /apis/rbac.authorization.k8s.io/v1"
},
{
"path": "/apis/rbac.authorization.k8s.io/v1beta1",
"description": "API at /apis/rbac.authorization.k8s.io/v1beta1"
},
{
"path": "/apis/rbac.authorization.k8s.io/v1alpha1",
"description": "API at /apis/rbac.authorization.k8s.io/v1alpha1"
},
......
......@@ -49,6 +49,10 @@ declare -a resources=(
"jobs"
"horizontalpodautoscalers"
"storageclasses"
"roles.rbac.authorization.k8s.io"
"rolebindings.rbac.authorization.k8s.io"
"clusterroles.rbac.authorization.k8s.io"
"clusterrolebindings.rbac.authorization.k8s.io"
)
# Find all the namespaces.
......
......@@ -57,13 +57,13 @@ go_test(
"//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/apis/rbac/v1beta1:go_default_library",
"//pkg/apis/rbac/v1:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
......
......@@ -55,7 +55,7 @@ go_test(
"//vendor/gopkg.in/gcfg.v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1beta1:go_default_library",
"//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
......
......@@ -35,7 +35,7 @@ import (
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
......@@ -785,10 +785,10 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
},
}
role := rbacv1beta1.Role{
role := rbacv1.Role{
TypeMeta: metav1.TypeMeta{
Kind: "Role",
APIVersion: rbacv1beta1.SchemeGroupVersion.String(),
APIVersion: rbacv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "federation-system:federation-controller-manager",
......@@ -798,7 +798,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
federation.FederationNameAnnotation: federationName,
},
},
Rules: []rbacv1beta1.PolicyRule{
Rules: []rbacv1.PolicyRule{
{
Verbs: []string{"get", "list", "watch"},
APIGroups: []string{""},
......@@ -807,10 +807,10 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
},
}
rolebinding := rbacv1beta1.RoleBinding{
rolebinding := rbacv1.RoleBinding{
TypeMeta: metav1.TypeMeta{
Kind: "RoleBinding",
APIVersion: rbacv1beta1.SchemeGroupVersion.String(),
APIVersion: rbacv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "federation-system:federation-controller-manager",
......@@ -820,7 +820,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
federation.FederationNameAnnotation: federationName,
},
},
Subjects: []rbacv1beta1.Subject{
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
APIGroup: "",
......@@ -828,7 +828,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Namespace: "federation-system",
},
},
RoleRef: rbacv1beta1.RoleRef{
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: "federation-system:federation-controller-manager",
......@@ -1137,8 +1137,8 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Name: rbac.GroupName,
Versions: []metav1.GroupVersionForDiscovery{
{
GroupVersion: rbac.GroupName + "/v1beta1",
Version: "v1beta1",
GroupVersion: rbac.GroupName + "/v1",
Version: "v1",
},
},
}
......@@ -1296,12 +1296,12 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
return nil, fmt.Errorf("unexpected service account object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, sa))
}
return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &sa)}, nil
case p == "/apis/rbac.authorization.k8s.io/v1beta1/namespaces/federation-system/roles" && m == http.MethodPost:
case p == "/apis/rbac.authorization.k8s.io/v1/namespaces/federation-system/roles" && m == http.MethodPost:
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
var got rbacv1beta1.Role
var got rbacv1.Role
_, _, err = codec.Decode(body, nil, &got)
if err != nil {
return nil, err
......@@ -1310,12 +1310,12 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
return nil, fmt.Errorf("unexpected role object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, role))
}
return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(rbacCodec, &role)}, nil
case p == "/apis/rbac.authorization.k8s.io/v1beta1/namespaces/federation-system/rolebindings" && m == http.MethodPost:
case p == "/apis/rbac.authorization.k8s.io/v1/namespaces/federation-system/rolebindings" && m == http.MethodPost:
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
var got rbacv1beta1.RoleBinding
var got rbacv1.RoleBinding
_, _, err = codec.Decode(body, nil, &got)
if err != nil {
return nil, err
......
......@@ -26,7 +26,7 @@ import (
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
......@@ -40,7 +40,7 @@ import (
"k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
k8srbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1"
k8srbacv1 "k8s.io/kubernetes/pkg/apis/rbac/v1"
"k8s.io/kubernetes/pkg/kubectl"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
......@@ -477,7 +477,7 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa
}
roleName := util.ClusterRoleName(testFederationName, saName)
clusterRole := rbacv1beta1.ClusterRole{
clusterRole := rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: roleName,
Namespace: util.DefaultFederationSystemNamespace,
......@@ -486,12 +486,12 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa
federation.ClusterNameAnnotation: clusterName,
},
},
Rules: []rbacv1beta1.PolicyRule{
k8srbacv1beta1.NewRule(rbacv1beta1.VerbAll).Groups(rbacv1beta1.APIGroupAll).Resources(rbacv1beta1.ResourceAll).RuleOrDie(),
Rules: []rbacv1.PolicyRule{
k8srbacv1.NewRule(rbacv1.VerbAll).Groups(rbacv1.APIGroupAll).Resources(rbacv1.ResourceAll).RuleOrDie(),
},
}
clusterRoleBinding, err := k8srbacv1beta1.NewClusterBinding(roleName).SAs(util.DefaultFederationSystemNamespace, saName).Binding()
clusterRoleBinding, err := k8srbacv1.NewClusterBinding(roleName).SAs(util.DefaultFederationSystemNamespace, saName).Binding()
if err != nil {
return nil, err
}
......@@ -509,11 +509,11 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa
apiGroupList.Groups = append(apiGroupList.Groups, testGroup)
if isRBACAPIAvailable {
rbacGroup := metav1.APIGroup{
Name: rbacv1beta1.GroupName,
Name: rbacv1.GroupName,
Versions: []metav1.GroupVersionForDiscovery{
{
GroupVersion: rbacv1beta1.GroupName + "/v1beta1",
Version: "v1beta1",
GroupVersion: rbacv1.GroupName + "/v1",
Version: "v1",
},
},
}
......@@ -544,9 +544,9 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx, dnsProvider, tmpDirPa
case p == "/api/v1/namespaces/federation-system/serviceaccounts" && m == http.MethodPost && r:
return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(defaultCodec, &serviceAccount)}, nil
case p == "/apis/rbac.authorization.k8s.io/v1beta1/clusterroles" && m == http.MethodPost && r:
case p == "/apis/rbac.authorization.k8s.io/v1/clusterroles" && m == http.MethodPost && r:
return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(rbacCodec, &clusterRole)}, nil
case p == "/apis/rbac.authorization.k8s.io/v1beta1/clusterrolebindings" && m == http.MethodPost && r:
case p == "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" && m == http.MethodPost && r:
return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(rbacCodec, &clusterRoleBinding)}, nil
case p == "/api/v1/namespaces/federation-system/secrets/serviceaccountsecret" && m == http.MethodGet && r:
......
......@@ -217,9 +217,9 @@ func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory {
func fakeUnjoinHostFactory(clusterName string) cmdutil.Factory {
secretsPrefix := "/api/v1/namespaces/federation-system/secrets/"
clusterRolePrefix := "/apis/rbac.authorization.k8s.io/v1beta1/clusterroles/"
clusterRolePrefix := "/apis/rbac.authorization.k8s.io/v1/clusterroles/"
serviceAccountPrefix := "/api/v1/namespaces/federation-system/serviceaccounts/"
clusterRoleBindingPrefix := "/apis/rbac.authorization.k8s.io/v1beta1/clusterrolebindings/"
clusterRoleBindingPrefix := "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/"
// Using dummy bytes for now
configBytes, _ := clientcmd.Write(clientcmdapi.Config{})
......
......@@ -40,16 +40,9 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
&announced.GroupMetaFactoryArgs{
GroupName: rbac.GroupName,
// Rollout plan:
// 1.8:
// * announce deprecation of v1alpha1 (people should use v1beta1 or v1)
// 1.9 (once all version-skewed API servers in an HA cluster are capable of reading/writing v1 to etcd):
// * move v1 to the beginning
// * add RBAC objects to update-storage-objects.sh
// * update TestEtcdStoragePath to expect objects to be stored in v1
// * document that RBAC storage objects should be migrated to ensure storage is a v1-level (via update-storage-objects.sh or otherwise)
// 1.10 (once all stored objects are at v1):
// * remove v1alpha1
VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version},
// * remove v1alpha1 (announced deprecated in 1.8)
VersionPreferenceOrder: []string{v1.SchemeGroupVersion.Version, v1beta1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version},
RootScopedKinds: sets.NewString("ClusterRole", "ClusterRoleBinding"),
AddInternalObjectsToScheme: rbac.AddToScheme,
},
......
......@@ -74,15 +74,14 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag
apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1alpha1.SchemeGroupVersion.Version] = p.storage(rbacapiv1alpha1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
apiGroupInfo.GroupMeta.GroupVersion = rbacapiv1alpha1.SchemeGroupVersion
}
// TODO: move this after v1beta1 in 1.9, so RBAC objects write to storage in v1
if apiResourceConfigSource.AnyResourcesForVersionEnabled(rbacapiv1.SchemeGroupVersion) {
apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1.SchemeGroupVersion.Version] = p.storage(rbacapiv1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
apiGroupInfo.GroupMeta.GroupVersion = rbacapiv1.SchemeGroupVersion
}
if apiResourceConfigSource.AnyResourcesForVersionEnabled(rbacapiv1beta1.SchemeGroupVersion) {
apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1beta1.SchemeGroupVersion.Version] = p.storage(rbacapiv1beta1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
apiGroupInfo.GroupMeta.GroupVersion = rbacapiv1beta1.SchemeGroupVersion
}
if apiResourceConfigSource.AnyResourcesForVersionEnabled(rbacapiv1.SchemeGroupVersion) {
apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1.SchemeGroupVersion.Version] = p.storage(rbacapiv1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
apiGroupInfo.GroupMeta.GroupVersion = rbacapiv1.SchemeGroupVersion
}
return apiGroupInfo, true
}
......
......@@ -286,22 +286,22 @@ var etcdStorageData = map[schema.GroupVersionResource]struct {
gvr("rbac.authorization.k8s.io", "v1alpha1", "roles"): {
stub: `{"metadata": {"name": "role1"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
expectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role1",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "Role"),
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "Role"),
},
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterroles"): {
stub: `{"metadata": {"name": "crole1"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
expectedEtcdPath: "/registry/clusterroles/crole1",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRole"),
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRole"),
},
gvr("rbac.authorization.k8s.io", "v1alpha1", "rolebindings"): {
stub: `{"metadata": {"name": "roleb1"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
expectedEtcdPath: "/registry/rolebindings/etcdstoragepathtestnamespace/roleb1",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "RoleBinding"),
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "RoleBinding"),
},
gvr("rbac.authorization.k8s.io", "v1alpha1", "clusterrolebindings"): {
stub: `{"metadata": {"name": "croleb1"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
expectedEtcdPath: "/registry/clusterrolebindings/croleb1",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRoleBinding"),
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"),
},
// --
......@@ -309,18 +309,22 @@ var etcdStorageData = map[schema.GroupVersionResource]struct {
gvr("rbac.authorization.k8s.io", "v1beta1", "roles"): {
stub: `{"metadata": {"name": "role2"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
expectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role2",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "Role"),
},
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterroles"): {
stub: `{"metadata": {"name": "crole2"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
expectedEtcdPath: "/registry/clusterroles/crole2",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRole"),
},
gvr("rbac.authorization.k8s.io", "v1beta1", "rolebindings"): {
stub: `{"metadata": {"name": "roleb2"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
expectedEtcdPath: "/registry/rolebindings/etcdstoragepathtestnamespace/roleb2",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "RoleBinding"),
},
gvr("rbac.authorization.k8s.io", "v1beta1", "clusterrolebindings"): {
stub: `{"metadata": {"name": "croleb2"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
expectedEtcdPath: "/registry/clusterrolebindings/croleb2",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1", "ClusterRoleBinding"),
},
// --
......@@ -328,22 +332,18 @@ var etcdStorageData = map[schema.GroupVersionResource]struct {
gvr("rbac.authorization.k8s.io", "v1", "roles"): {
stub: `{"metadata": {"name": "role3"}, "rules": [{"apiGroups": ["v1"], "resources": ["events"], "verbs": ["watch"]}]}`,
expectedEtcdPath: "/registry/roles/etcdstoragepathtestnamespace/role3",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "Role"),
},
gvr("rbac.authorization.k8s.io", "v1", "clusterroles"): {
stub: `{"metadata": {"name": "crole3"}, "rules": [{"nonResourceURLs": ["/version"], "verbs": ["get"]}]}`,
expectedEtcdPath: "/registry/clusterroles/crole3",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRole"),
},
gvr("rbac.authorization.k8s.io", "v1", "rolebindings"): {
stub: `{"metadata": {"name": "roleb3"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
expectedEtcdPath: "/registry/rolebindings/etcdstoragepathtestnamespace/roleb3",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "RoleBinding"),
},
gvr("rbac.authorization.k8s.io", "v1", "clusterrolebindings"): {
stub: `{"metadata": {"name": "croleb3"}, "roleRef": {"apiGroup": "rbac.authorization.k8s.io", "kind": "ClusterRole", "name": "somecr"}, "subjects": [{"apiVersion": "rbac.authorization.k8s.io/v1alpha1", "kind": "Group", "name": "system:authenticated"}]}`,
expectedEtcdPath: "/registry/clusterrolebindings/croleb3",
expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRoleBinding"),
},
// --
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment