stackube/pkg/auth-controller/rbacmanager/rbac_controller.go
Pengfei Ni 50322401cd Add kube-dns
Adds kube-dns deployments for each tenant. And also adds loadbalancer
for cluster DNS in each namespace.

Implements: blueprint dns
Change-Id: I2ee00806431cc4a3dfdf4c3c49b54892d4c2c98b
Signed-off-by: Pengfei Ni <feiskyer@gmail.com>
2017-08-04 08:56:27 +08:00

213 lines
6.0 KiB
Go

/*
Copyright (c) 2017 OpenStack Foundation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rbacmanager
import (
"time"
crv1 "git.openstack.org/openstack/stackube/pkg/apis/v1"
"git.openstack.org/openstack/stackube/pkg/auth-controller/rbacmanager/rbac"
crdClient "git.openstack.org/openstack/stackube/pkg/kubecrd"
"git.openstack.org/openstack/stackube/pkg/util"
"github.com/golang/glog"
apiv1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
)
const (
resyncPeriod = 5 * time.Minute
)
// Controller manages life cycle of namespace's rbac.
type Controller struct {
k8sclient *kubernetes.Clientset
kubeCRDClient *crdClient.CRDClient
userCIDR string
userGateway string
}
// NewRBACController creates a new RBAC controller.
func NewRBACController(kubeClient *kubernetes.Clientset, kubeCRDClient *crdClient.CRDClient, userCIDR string,
userGateway string) (*Controller, error) {
c := &Controller{
k8sclient: kubeClient,
kubeCRDClient: kubeCRDClient,
userCIDR: userCIDR,
userGateway: userGateway,
}
return c, nil
}
// Run the controller.
func (c *Controller) Run(stopCh <-chan struct{}) error {
defer utilruntime.HandleCrash()
source := cache.NewListWatchFromClient(
c.k8sclient.Core().RESTClient(),
"namespaces",
apiv1.NamespaceAll,
fields.Everything())
_, namespaceInformor := cache.NewInformer(
source,
&apiv1.Namespace{},
resyncPeriod,
cache.ResourceEventHandlerFuncs{
AddFunc: c.onAdd,
UpdateFunc: c.onUpdate,
DeleteFunc: c.onDelete,
})
go namespaceInformor.Run(stopCh)
<-stopCh
return nil
}
func (c *Controller) onAdd(obj interface{}) {
namespace := obj.(*apiv1.Namespace)
glog.V(3).Infof("RBAC controller received new object %#v\n", namespace)
// Check if this is a system reserved namespace
if util.IsSystemNamespace(namespace.Name) {
if err := c.initSystemReservedTenantNetwork(); err != nil {
glog.Error(err)
return
}
return
} else {
if err := c.createNetworkForTenant(namespace.Name); err != nil {
glog.Error(err)
return
}
}
glog.V(4).Infof("Added namespace %s", namespace.Name)
c.syncRBAC(namespace)
}
// createNetworkForTenant automatically create network for given non-system tenant
func (c *Controller) createNetworkForTenant(namespace string) error {
network := &crv1.Network{
ObjectMeta: metav1.ObjectMeta{
// use the namespace name as network
Name: namespace,
Namespace: namespace,
},
Spec: crv1.NetworkSpec{
CIDR: c.userCIDR,
Gateway: c.userGateway,
},
}
// network controller will always check if Tenant is ready so we will not wait here
if err := c.kubeCRDClient.AddNetwork(network); err != nil {
return err
}
return nil
}
// initSystemReservedTenantNetwork automatically create tenant network for system namespace
func (c *Controller) initSystemReservedTenantNetwork() error {
tenant := &crv1.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: util.SystemTenant,
// always add tenant to system namespace
Namespace: util.SystemTenant,
},
Spec: crv1.TenantSpec{
UserName: util.SystemTenant,
Password: util.SystemPassword,
},
}
if err := c.kubeCRDClient.AddTenant(tenant); err != nil {
return err
}
// NOTE(harry): we do not support update Network, so although configurable,
// user can not update CIDR by changing the configuration, unless manually delete
// that system network. We may need to document this.
network := &crv1.Network{
ObjectMeta: metav1.ObjectMeta{
Name: util.SystemNetwork,
Namespace: util.SystemTenant,
},
Spec: crv1.NetworkSpec{
CIDR: c.userCIDR,
Gateway: c.userGateway,
},
}
// network controller will always check if Tenant is ready so we will not wait here
if err := c.kubeCRDClient.AddNetwork(network); err != nil {
return err
}
return nil
}
func (c *Controller) onUpdate(obj1, obj2 interface{}) {
// NOTE(mozhuli) not supported yet
}
func (c *Controller) onDelete(obj interface{}) {
namespace := obj.(*apiv1.Namespace)
// tenant controller have done all the works so we will not wait here
glog.V(3).Infof("RBAC controller received deleted namespace %#v\n", namespace)
}
func (c *Controller) syncRBAC(ns *apiv1.Namespace) error {
if ns.DeletionTimestamp != nil {
return nil
}
rbacClient := c.k8sclient.Rbac()
// Create role for tenant
role := rbac.GenerateRoleByNamespace(ns.Name)
_, err := rbacClient.Roles(ns.Name).Create(role)
if err != nil && !apierrors.IsAlreadyExists(err) {
glog.Errorf("Failed create default-role in namespace %s for tenant %s: %v", ns.Name, ns.Name, err)
return err
}
glog.V(4).Infof("Created default-role in namespace %s for tenant %s", ns.Name, ns.Name)
// Create rolebinding for tenant
roleBinding := rbac.GenerateRoleBinding(ns.Name, ns.Name)
_, err = rbacClient.RoleBindings(ns.Name).Create(roleBinding)
if err != nil && !apierrors.IsAlreadyExists(err) {
glog.Errorf("Failed create %s-rolebindings in namespace %s for tenant %s: %v", ns.Name, ns.Name, ns.Name, err)
return err
}
saRoleBinding := rbac.GenerateServiceAccountRoleBinding(ns.Name, ns.Name)
_, err = rbacClient.RoleBindings(ns.Name).Create(saRoleBinding)
if err != nil && !apierrors.IsAlreadyExists(err) {
glog.Errorf("Failed create %s-rolebindings-sa in namespace %s for tenant %s: %v", ns.Name, ns.Name, ns.Name, err)
return err
}
glog.V(4).Infof("Created %s-rolebindings in namespace %s for tenant %s", ns.Name, ns.Name, ns.Name)
return nil
}