Skip to content
This repository has been archived by the owner on Sep 22, 2020. It is now read-only.

Commit

Permalink
Issue 46: Add role bindings with edit access (#23)
Browse files Browse the repository at this point in the history
* Add rolebindings for dev and stage namespace

Co-authored-by: ishitasequeira <isequeir@redhat.com>

* Fix dockerconfigjson secret namespace and name swap issue. Move sources to func in main driver. (#17)

* Fix dockerconfigjson secret namespace and name swap issue. Move sources to func in main driver. (#17)

Co-authored-by: ishitasequeira <isequeir@redhat.com>

* made changes mentioned in the PR
renamed devRoleBindingName and stageRoleBindingName and created rolebindings

Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
Co-authored-by: William Tam <wtam@redhat.com>
  • Loading branch information
3 people authored and bigkevmcd committed Mar 3, 2020
1 parent dca8cbb commit a50e07f
Showing 1 changed file with 155 additions and 152 deletions.
307 changes: 155 additions & 152 deletions pkg/pipelines/bootstrap.go
Original file line number Diff line number Diff line change
@@ -1,196 +1,199 @@
package pipelines

import (
"errors"
"fmt"
"io"
"os"

corev1 "k8s.io/api/core/v1"
v1rbac "k8s.io/api/rbac/v1"

"github.com/mitchellh/go-homedir"
"github.com/openshift/odo/pkg/pipelines/eventlisteners"
"github.com/openshift/odo/pkg/pipelines/meta"
"github.com/openshift/odo/pkg/pipelines/routes"
"github.com/openshift/odo/pkg/pipelines/tasks"
"github.com/openshift/odo/pkg/pipelines/triggers"
"sigs.k8s.io/yaml"
"errors"
"fmt"
"io"
"os"

corev1 "k8s.io/api/core/v1"
v1rbac "k8s.io/api/rbac/v1"

"github.com/mitchellh/go-homedir"
"github.com/openshift/odo/pkg/pipelines/eventlisteners"
"github.com/openshift/odo/pkg/pipelines/meta"
"github.com/openshift/odo/pkg/pipelines/routes"
"github.com/openshift/odo/pkg/pipelines/tasks"
"github.com/openshift/odo/pkg/pipelines/triggers"
"sigs.k8s.io/yaml"
)

var (
dockerSecretName = "regcred"
saName = "pipeline"
roleName = "tekton-triggers-openshift-demo"
roleBindingName = "tekton-triggers-openshift-binding"

// PolicyRules to be bound to service account
rules = []v1rbac.PolicyRule{
v1rbac.PolicyRule{
APIGroups: []string{"tekton.dev"},
Resources: []string{"eventlisteners", "triggerbindings", "triggertemplates", "tasks", "taskruns"},
Verbs: []string{"get"},
},
v1rbac.PolicyRule{
APIGroups: []string{"tekton.dev"},
Resources: []string{"pipelineruns", "pipelineresources", "taskruns"},
Verbs: []string{"create"},
},
}
dockerSecretName = "regcred"
saName = "pipeline"
roleName = "tekton-triggers-openshift-demo"
roleBindingName = "tekton-triggers-openshift-binding"
devRoleBindingName = "pipeline-admin-dev"
stageRoleBindingName = "pipeline-admin-stage"
// PolicyRules to be bound to service account
rules = []v1rbac.PolicyRule{
v1rbac.PolicyRule{
APIGroups: []string{"tekton.dev"},
Resources: []string{"eventlisteners", "triggerbindings", "triggertemplates", "tasks", "taskruns"},
Verbs: []string{"get"},
},
v1rbac.PolicyRule{
APIGroups: []string{"tekton.dev"},
Resources: []string{"pipelineruns", "pipelineresources", "taskruns"},
Verbs: []string{"create"},
},
}
)

// BootstrapOptions is a struct that provides the optional flags
type BootstrapOptions struct {
DeploymentPath string
GithubToken string
GitRepo string
Prefix string
QuayAuthFileName string
QuayUserName string
SkipChecks bool
DeploymentPath string
GithubToken string
GitRepo string
Prefix string
QuayAuthFileName string
QuayUserName string
SkipChecks bool
}

// Bootstrap is the main driver for getting OpenShift pipelines for GitOps
// configured with a basic configuration.
func Bootstrap(o *BootstrapOptions) error {
// First, check for Tekton. We proceed only if Tekton is installed
if !o.SkipChecks {
installed, err := checkTektonInstall()
if err != nil {
return fmt.Errorf("failed to run Tekton Pipelines installation check: %w", err)
}
if !installed {
return errors.New("failed due to Tekton Pipelines or Triggers are not installed")
}
}
outputs := make([]interface{}, 0)
namespaces := namespaceNames(o.Prefix)
for _, n := range createNamespaces(values(namespaces)) {
outputs = append(outputs, n)
}

githubAuth, err := createOpaqueSecret(meta.NamespacedName(namespaces["cicd"], "github-auth"), o.GithubToken)
if err != nil {
return fmt.Errorf("failed to generate path to file: %w", err)
}
outputs = append(outputs, githubAuth)

// Create Docker Secret
dockerSecret, err := createDockerSecret(o.QuayAuthFileName, namespaces["cicd"])
if err != nil {
return err
}
outputs = append(outputs, dockerSecret)

// Create Tasks
tasks := tasks.Generate(githubAuth.GetName(), namespaces["cicd"])
for _, task := range tasks {
outputs = append(outputs, task)
}

// Create trigger templates
templates := triggers.GenerateTemplates(namespaces["cicd"], saName)
for _, template := range templates {
outputs = append(outputs, template)
}

// Create trigger bindings
bindings := triggers.GenerateBindings(namespaces["cicd"])
for _, binding := range bindings {
outputs = append(outputs, binding)
}

// Create Pipelines
outputs = append(outputs, createPipelines(namespaces, o.DeploymentPath)...)

// Create Event Listener
eventListener := eventlisteners.Generate(o.GitRepo, namespaces["cicd"], saName)
outputs = append(outputs, eventListener)

// Create route
route := routes.Generate(namespaces["cicd"])
outputs = append(outputs, route)

// Create Service Account, Role, Role Bindings, and ClusterRole Bindings
outputs = append(outputs, createRoleBindings(namespaces)...)

return marshalOutputs(os.Stdout, outputs)
// First, check for Tekton. We proceed only if Tekton is installed
if !o.SkipChecks {
installed, err := checkTektonInstall()
if err != nil {
return fmt.Errorf("failed to run Tekton Pipelines installation check: %w", err)
}
if !installed {
return errors.New("failed due to Tekton Pipelines or Triggers are not installed")
}
}
outputs := make([]interface{}, 0)
namespaces := namespaceNames(o.Prefix)
for _, n := range createNamespaces(values(namespaces)) {
outputs = append(outputs, n)
}

githubAuth, err := createOpaqueSecret(meta.NamespacedName(namespaces["cicd"], "github-auth"), o.GithubToken)
if err != nil {
return fmt.Errorf("failed to generate path to file: %w", err)
}
outputs = append(outputs, githubAuth)

// Create Docker Secret
dockerSecret, err := createDockerSecret(o.QuayAuthFileName, namespaces["cicd"])
if err != nil {
return err
}
outputs = append(outputs, dockerSecret)

// Create Tasks
tasks := tasks.Generate(githubAuth.GetName(), namespaces["cicd"])
for _, task := range tasks {
outputs = append(outputs, task)
}

// Create trigger templates
templates := triggers.GenerateTemplates(namespaces["cicd"], saName)
for _, template := range templates {
outputs = append(outputs, template)
}

// Create trigger bindings
bindings := triggers.GenerateBindings(namespaces["cicd"])
for _, binding := range bindings {
outputs = append(outputs, binding)
}

// Create Pipelines
outputs = append(outputs, createPipelines(namespaces, o.DeploymentPath)...)

// Create Event Listener
eventListener := eventlisteners.Generate(o.GitRepo, namespaces["cicd"], saName)
outputs = append(outputs, eventListener)

// Create route
route := routes.Generate(namespaces["cicd"])
outputs = append(outputs, route)

// Create Service Account, Role, Role Bindings, and ClusterRole Bindings
outputs = append(outputs, createRoleBindings(namespaces)...)

return marshalOutputs(os.Stdout, outputs)
}

func createRoleBindings(ns map[string]string) []interface{} {
out := make([]interface{}, 0)
sa := createServiceAccount(meta.NamespacedName(ns["cicd"], saName), dockerSecretName)
out = append(out, sa)
role := createRole(meta.NamespacedName(ns["cicd"], roleName), rules)
out = append(out, role)
out = append(out, createRoleBinding(meta.NamespacedName(ns["cicd"], roleBindingName), sa, role.Kind, role.Name))
out = append(out, createRoleBinding(meta.NamespacedName(ns["cicd"], "edit-clusterrole-binding"), sa, "ClusterRole", "edit"))
return out
out := make([]interface{}, 0)
sa := createServiceAccount(meta.NamespacedName(ns["cicd"], saName), dockerSecretName)
out = append(out, sa)
role := createRole(meta.NamespacedName(ns["cicd"], roleName), rules)
out = append(out, role)
out = append(out, createRoleBinding(meta.NamespacedName(ns["cicd"], roleBindingName), sa, role.Kind, role.Name))
out = append(out, createRoleBinding(meta.NamespacedName(ns["cicd"], "edit-clusterrole-binding"), sa, "ClusterRole", "edit"))
out = append(out, createRoleBinding(meta.NamespacedName(ns["dev"], devRoleBindingName), sa, "ClusterRole", "edit"))
out = append(out, createRoleBinding(meta.NamespacedName(ns["stage"], stageRoleBindingName), sa, "ClusterRole", "edit"))

return out
}

func createPipelines(ns map[string]string, deploymentPath string) []interface{} {
out := make([]interface{}, 0)
out = append(out, createDevCIPipeline(meta.NamespacedName(ns["cicd"], "dev-ci-pipeline")))
out = append(out, createStageCIPipeline(meta.NamespacedName(ns["cicd"], "stage-ci-pipeline"), ns["stage"]))
out = append(out, createDevCDPipeline(meta.NamespacedName(ns["cicd"], "dev-cd-pipeline"), deploymentPath, ns["dev"]))
out = append(out, createStageCDPipeline(meta.NamespacedName(ns["cicd"], "stage-cd-pipeline"), ns["stage"]))
return out
out := make([]interface{}, 0)
out = append(out, createDevCIPipeline(meta.NamespacedName(ns["cicd"], "dev-ci-pipeline")))
out = append(out, createStageCIPipeline(meta.NamespacedName(ns["cicd"], "stage-ci-pipeline"), ns["stage"]))
out = append(out, createDevCDPipeline(meta.NamespacedName(ns["cicd"], "dev-cd-pipeline"), deploymentPath, ns["dev"]))
out = append(out, createStageCDPipeline(meta.NamespacedName(ns["cicd"], "stage-cd-pipeline"), ns["stage"]))
return out

}

// createDockerSecret creates Docker secret
func createDockerSecret(quayIOAuthFilename, ns string) (*corev1.Secret, error) {

authJSONPath, err := homedir.Expand(quayIOAuthFilename)
if err != nil {
return nil, fmt.Errorf("failed to generate path to file: %w", err)
}
authJSONPath, err := homedir.Expand(quayIOAuthFilename)
if err != nil {
return nil, fmt.Errorf("failed to generate path to file: %w", err)
}

f, err := os.Open(authJSONPath)
if err != nil {
return nil, fmt.Errorf("failed to read docker file '%s' : %w", authJSONPath, err)
}
defer f.Close()
f, err := os.Open(authJSONPath)
if err != nil {
return nil, fmt.Errorf("failed to read docker file '%s' : %w", authJSONPath, err)
}
defer f.Close()

dockerSecret, err := createDockerConfigSecret(meta.NamespacedName(ns, dockerSecretName), f)
if err != nil {
return nil, err
}
dockerSecret, err := createDockerConfigSecret(meta.NamespacedName(ns, dockerSecretName), f)
if err != nil {
return nil, err
}

return dockerSecret, nil
return dockerSecret, nil

}

// create and invoke a Tekton Checker
func checkTektonInstall() (bool, error) {
tektonChecker, err := newTektonChecker()
if err != nil {
return false, err
}
return tektonChecker.checkInstall()
tektonChecker, err := newTektonChecker()
if err != nil {
return false, err
}
return tektonChecker.checkInstall()
}

func values(m map[string]string) []string {
values := []string{}
for _, v := range m {
values = append(values, v)
values := []string{}
for _, v := range m {
values = append(values, v)

}
return values
}
return values
}

// marshalOutputs marshal outputs to given writer
func marshalOutputs(out io.Writer, outputs []interface{}) error {
for _, r := range outputs {
data, err := yaml.Marshal(r)
if err != nil {
return fmt.Errorf("failed to marshal data: %w", err)
}
_, err = fmt.Fprintf(out, "%s---\n", data)
if err != nil {
return fmt.Errorf("failed to write data: %w", err)
}
}
return nil
for _, r := range outputs {
data, err := yaml.Marshal(r)
if err != nil {
return fmt.Errorf("failed to marshal data: %w", err)
}
_, err = fmt.Fprintf(out, "%s---\n", data)
if err != nil {
return fmt.Errorf("failed to write data: %w", err)
}
}
return nil
}

0 comments on commit a50e07f

Please sign in to comment.