Enabling multi-tenancy for fission objects. (#655)
This feature allows creation of fission objects in different namespaces, in addition to retaining the existing behavior of creating fission objects in default namespace if user doesnt provide one. It also removes cluster admin roles for fission-fetcher and fission-builder Service Accounts and grants them only those privileges that they need.
This commit is contained in:
@@ -50,14 +50,14 @@ const (
|
||||
)
|
||||
|
||||
func (deploy *NewDeploy) createOrGetDeployment(fn *crd.Function, env *crd.Environment,
|
||||
deployName string, deployLabels map[string]string) (*v1beta1.Deployment, error) {
|
||||
deployName string, deployLabels map[string]string, deployNamespace string) (*v1beta1.Deployment, error) {
|
||||
|
||||
replicas := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
|
||||
if replicas == 0 {
|
||||
replicas = 1
|
||||
}
|
||||
|
||||
existingDepl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Get(deployName, metav1.GetOptions{})
|
||||
existingDepl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deployNamespace).Get(deployName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
if existingDepl.Status.ReadyReplicas < replicas {
|
||||
existingDepl, err = deploy.waitForDeploy(existingDepl, replicas)
|
||||
@@ -66,13 +66,17 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *crd.Function, env *crd.Enviro
|
||||
}
|
||||
|
||||
if err != nil && k8s_err.IsNotFound(err) {
|
||||
err := deploy.setupRBACObjs(deployNamespace, fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deployment, err := deploy.getDeploymentSpec(fn, env, deployName, deployLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
depl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Create(deployment)
|
||||
depl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deployNamespace).Create(deployment)
|
||||
if err != nil {
|
||||
log.Printf("Error while creating deployment: %v", err)
|
||||
return nil, err
|
||||
@@ -85,13 +89,39 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *crd.Function, env *crd.Enviro
|
||||
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) getDeployment(fn *crd.Function) (*v1beta1.Deployment, error) {
|
||||
deployName := deploy.getObjName(fn)
|
||||
return deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Get(deployName, metav1.GetOptions{})
|
||||
func (deploy *NewDeploy) setupRBACObjs(deployNamespace string, fn *crd.Function) error {
|
||||
// create fetcher SA in this ns, if not already created
|
||||
_, err := fission.SetupSA(deploy.kubernetesClient, fission.FissionFetcherSA, deployNamespace)
|
||||
if err != nil {
|
||||
log.Printf("Error : %v creating %s in ns : %s for function: %s.%s", err, fission.FissionFetcherSA, deployNamespace, fn.Metadata.Name, fn.Metadata.Namespace)
|
||||
return err
|
||||
}
|
||||
|
||||
// create a cluster role binding for the fetcher SA, if not already created, granting access to do a get on packages in any ns
|
||||
err = fission.SetupRoleBinding(deploy.kubernetesClient, fission.PackageGetterRB, fn.Spec.Package.PackageRef.Namespace, fission.PackageGetterCR, fission.ClusterRole, fission.FissionFetcherSA, deployNamespace)
|
||||
if err != nil {
|
||||
log.Printf("Error : %v creating %s RoleBinding for function: %s.%s", err, fission.PackageGetterRB, fn.Metadata.Name, fn.Metadata.Namespace)
|
||||
return err
|
||||
}
|
||||
|
||||
// create rolebinding in function namespace for fetcherSA.envNamespace to be able to get secrets and configmaps
|
||||
err = fission.SetupRoleBinding(deploy.kubernetesClient, fission.SecretConfigMapGetterRB, fn.Metadata.Namespace, fission.SecretConfigMapGetterCR, fission.ClusterRole, fission.FissionFetcherSA, deployNamespace)
|
||||
if err != nil {
|
||||
log.Printf("Error : %v creating %s RoleBinding for function %s.%s", err, fission.SecretConfigMapGetterRB, fn.Metadata.Name, fn.Metadata.Namespace)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Set up all RBAC objects for function : %s.%s", fn.Metadata.Name, fn.Metadata.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) updateDeployment(deployment *v1beta1.Deployment) error {
|
||||
_, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Update(deployment)
|
||||
func (deploy *NewDeploy) getDeployment(fn *crd.Function) (*v1beta1.Deployment, error) {
|
||||
deployName := deploy.getObjName(fn)
|
||||
return deploy.kubernetesClient.ExtensionsV1beta1().Deployments(fn.Metadata.Namespace).Get(deployName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) updateDeployment(deployment *v1beta1.Deployment, ns string) error {
|
||||
_, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(ns).Update(deployment)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -115,7 +145,9 @@ func (deploy *NewDeploy) getDeploymentSpec(fn *crd.Function, env *crd.Environmen
|
||||
if replicas == 0 {
|
||||
replicas = 1
|
||||
}
|
||||
|
||||
targetFilename := "user"
|
||||
|
||||
gracePeriodSeconds := int64(6 * 60)
|
||||
if env.Spec.TerminationGracePeriod > 0 {
|
||||
gracePeriodSeconds = env.Spec.TerminationGracePeriod
|
||||
@@ -351,7 +383,7 @@ func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fission.Ex
|
||||
maxRepl := int32(execStrategy.MaxScale)
|
||||
targetCPU := int32(execStrategy.TargetCPUPercent)
|
||||
|
||||
existingHpa, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(deploy.namespace).Get(hpaName, metav1.GetOptions{})
|
||||
existingHpa, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(depl.ObjectMeta.Namespace).Get(hpaName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return existingHpa, err
|
||||
}
|
||||
@@ -364,7 +396,7 @@ func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fission.Ex
|
||||
hpa := asv1.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: hpaName,
|
||||
Namespace: deploy.namespace,
|
||||
Namespace: depl.ObjectMeta.Namespace,
|
||||
Labels: depl.Labels,
|
||||
},
|
||||
Spec: asv1.HorizontalPodAutoscalerSpec{
|
||||
@@ -379,7 +411,7 @@ func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fission.Ex
|
||||
},
|
||||
}
|
||||
|
||||
cHpa, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(deploy.namespace).Create(&hpa)
|
||||
cHpa, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(depl.ObjectMeta.Namespace).Create(&hpa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -392,11 +424,11 @@ func (deploy *NewDeploy) createOrGetHpa(hpaName string, execStrategy *fission.Ex
|
||||
|
||||
func (deploy *NewDeploy) getHpa(fn *crd.Function) (*asv1.HorizontalPodAutoscaler, error) {
|
||||
hpaName := deploy.getObjName(fn)
|
||||
return deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(deploy.namespace).Get(hpaName, metav1.GetOptions{})
|
||||
return deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(fn.Metadata.Namespace).Get(hpaName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) updateHpa(hpa *asv1.HorizontalPodAutoscaler) error {
|
||||
_, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(deploy.namespace).Update(hpa)
|
||||
_, err := deploy.kubernetesClient.AutoscalingV1().HorizontalPodAutoscalers(hpa.ObjectMeta.Namespace).Update(hpa)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -405,9 +437,9 @@ func (deploy *NewDeploy) deleteHpa(ns string, name string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (deploy *NewDeploy) createOrGetSvc(deployLabels map[string]string, svcName string) (*apiv1.Service, error) {
|
||||
func (deploy *NewDeploy) createOrGetSvc(deployLabels map[string]string, svcName string, svcNamespace string) (*apiv1.Service, error) {
|
||||
|
||||
existingSvc, err := deploy.kubernetesClient.CoreV1().Services(deploy.namespace).Get(svcName, metav1.GetOptions{})
|
||||
existingSvc, err := deploy.kubernetesClient.CoreV1().Services(svcNamespace).Get(svcName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return existingSvc, err
|
||||
}
|
||||
@@ -436,7 +468,7 @@ func (deploy *NewDeploy) createOrGetSvc(deployLabels map[string]string, svcName
|
||||
},
|
||||
}
|
||||
|
||||
svc, err := deploy.kubernetesClient.CoreV1().Services(deploy.namespace).Create(service)
|
||||
svc, err := deploy.kubernetesClient.CoreV1().Services(svcNamespace).Create(service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -457,7 +489,7 @@ func (deploy *NewDeploy) deleteSvc(ns string, name string) error {
|
||||
|
||||
func (deploy *NewDeploy) waitForDeploy(depl *v1beta1.Deployment, replicas int32) (*v1beta1.Deployment, error) {
|
||||
for i := 0; i < 120; i++ {
|
||||
latestDepl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(deploy.namespace).Get(depl.Name, metav1.GetOptions{})
|
||||
latestDepl, err := deploy.kubernetesClient.ExtensionsV1beta1().Deployments(depl.ObjectMeta.Namespace).Get(depl.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (deploy *NewDeploy) Run(ctx context.Context) {
|
||||
|
||||
func (deploy *NewDeploy) initFuncController() (k8sCache.Store, k8sCache.Controller) {
|
||||
resyncPeriod := 30 * time.Second
|
||||
listWatch := k8sCache.NewListWatchFromClient(deploy.crdClient, "functions", metav1.NamespaceDefault, fields.Everything())
|
||||
listWatch := k8sCache.NewListWatchFromClient(deploy.crdClient, "functions", metav1.NamespaceAll, fields.Everything())
|
||||
store, controller := k8sCache.NewInformer(listWatch, &crd.Function{}, resyncPeriod, k8sCache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
fn := obj.(*crd.Function)
|
||||
@@ -287,19 +287,26 @@ func (deploy *NewDeploy) fnCreate(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
|
||||
deployLabels := deploy.getDeployLabels(fn, env)
|
||||
|
||||
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
||||
// deployment of the function in fission-function ns
|
||||
ns := deploy.namespace
|
||||
if fn.Metadata.Namespace != metav1.NamespaceDefault {
|
||||
ns = fn.Metadata.Namespace
|
||||
}
|
||||
|
||||
// Envoy(istio-proxy) returns 404 directly before istio pilot
|
||||
// propagates latest Envoy-specific configuration.
|
||||
// Since newdeploy waits for pods of deployment to be ready,
|
||||
// change the order of kubeObject creation (create service first,
|
||||
// then deployment) to take advantage of waiting time.
|
||||
svc, err := deploy.createOrGetSvc(deployLabels, objName)
|
||||
svc, err := deploy.createOrGetSvc(deployLabels, objName, ns)
|
||||
if err != nil {
|
||||
log.Printf("Error creating the service %v: %v", objName, err)
|
||||
return fsvc, err
|
||||
}
|
||||
svcAddress := fmt.Sprintf("%v.%v", svc.Name, svc.Namespace)
|
||||
|
||||
depl, err := deploy.createOrGetDeployment(fn, env, objName, deployLabels)
|
||||
depl, err := deploy.createOrGetDeployment(fn, env, objName, deployLabels, ns)
|
||||
if err != nil {
|
||||
log.Printf("Error creating the deployment %v: %v", objName, err)
|
||||
return fsvc, err
|
||||
@@ -468,7 +475,15 @@ func (deploy *NewDeploy) fnUpdate(oldFn *crd.Function, newFn *crd.Function) {
|
||||
updateStatus(oldFn, err, "failed to get new deployment spec while updating function")
|
||||
return
|
||||
}
|
||||
err = deploy.updateDeployment(newDeployment)
|
||||
|
||||
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
||||
// deployment of the function in fission-function ns
|
||||
ns := deploy.namespace
|
||||
if newFn.Metadata.Namespace != metav1.NamespaceDefault {
|
||||
ns = newFn.Metadata.Namespace
|
||||
}
|
||||
|
||||
err = deploy.updateDeployment(newDeployment, ns)
|
||||
if err != nil {
|
||||
updateStatus(oldFn, err, "failed to update deployment while updating function")
|
||||
return
|
||||
@@ -499,19 +514,26 @@ func (deploy *NewDeploy) fnDelete(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
}
|
||||
objName := fsvc.Name
|
||||
|
||||
err = deploy.deleteDeployment(deploy.namespace, objName)
|
||||
// to support backward compatibility, if the function was created in default ns, we fall back to creating the
|
||||
// deployment of the function in fission-function ns, so cleaning up resources there
|
||||
ns := deploy.namespace
|
||||
if fn.Metadata.Namespace != metav1.NamespaceDefault {
|
||||
ns = fn.Metadata.Namespace
|
||||
}
|
||||
|
||||
err = deploy.deleteDeployment(ns, objName)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting the deployment: %v", objName)
|
||||
delError = err
|
||||
}
|
||||
|
||||
err = deploy.deleteSvc(deploy.namespace, objName)
|
||||
err = deploy.deleteSvc(ns, objName)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting the service: %v", objName)
|
||||
delError = err
|
||||
}
|
||||
|
||||
err = deploy.deleteHpa(deploy.namespace, objName)
|
||||
err = deploy.deleteHpa(ns, objName)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting the HPA: %v", objName)
|
||||
delError = err
|
||||
@@ -520,6 +542,7 @@ func (deploy *NewDeploy) fnDelete(fn *crd.Function) (*fscache.FuncSvc, error) {
|
||||
if delError != nil {
|
||||
return nil, delError
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user