Skip to content

Commit

Permalink
Merge pull request #16218 from juanvallejo/jvallejo/add-output-dry-ru…
Browse files Browse the repository at this point in the history
…n-oc-adm-policy

Automatic merge from submit-queue (batch tested with PRs 16439, 16218, 16387, 16509)

add --output & --dry-run options to oc-adm-policy sub-commands  

Fixes #14808

Adds `--output` flags with support for json and yaml output to every `oc adm policy` sub-command, as well as `--dry-run` flag support to several sub-commands.

~~Still have a few sub-commands left to update, but opening PR to begin gathering any feedback.~~

cc @openshift/cli-review
  • Loading branch information
openshift-merge-robot committed Sep 23, 2017
2 parents fc7190d + 609c558 commit 846c827
Show file tree
Hide file tree
Showing 18 changed files with 3,153 additions and 51 deletions.
285 changes: 285 additions & 0 deletions contrib/completions/bash/oadm

Large diffs are not rendered by default.

410 changes: 410 additions & 0 deletions contrib/completions/bash/oc

Large diffs are not rendered by default.

695 changes: 695 additions & 0 deletions contrib/completions/bash/openshift

Large diffs are not rendered by default.

285 changes: 285 additions & 0 deletions contrib/completions/zsh/oadm

Large diffs are not rendered by default.

410 changes: 410 additions & 0 deletions contrib/completions/zsh/oc

Large diffs are not rendered by default.

695 changes: 695 additions & 0 deletions contrib/completions/zsh/openshift

Large diffs are not rendered by default.

128 changes: 108 additions & 20 deletions pkg/oc/admin/policy/modify_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/spf13/cobra"

kapierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
Expand Down Expand Up @@ -47,6 +49,11 @@ type RoleModificationOptions struct {
Users []string
Groups []string
Subjects []kapi.ObjectReference

DryRun bool
Output string

PrintObj func(obj runtime.Object) error
}

// NewCmdAddRoleToGroup implements the OpenShift cli add-role-to-group command
Expand All @@ -58,22 +65,26 @@ func NewCmdAddRoleToGroup(name, fullName string, f *clientcmd.Factory, out io.Wr
Short: "Add a role to groups for the current project",
Long: `Add a role to groups for the current project`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(f, args, &options.Groups, "group", true); err != nil {
if err := options.Complete(f, cmd, args, &options.Groups, "group", true, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.AddRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, true, "group", options.Targets, true, out)

if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, true, "group", options.Targets, true, options.DryRun, out)
}
},
}

cmd.Flags().StringVar(&options.RoleBindingName, "rolebinding-name", "", "Name of the rolebinding to modify or create. If left empty, appends to the first rolebinding found for the given role")
cmd.Flags().StringVar(&options.RoleNamespace, "role-namespace", "", "namespace where the role is located: empty means a role defined in cluster policy")

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -88,22 +99,26 @@ func NewCmdAddRoleToUser(name, fullName string, f *clientcmd.Factory, out io.Wri
Long: `Add a role to users or serviceaccounts for the current project`,
Example: fmt.Sprintf(addRoleToUserExample, fullName),
Run: func(cmd *cobra.Command, args []string) {
if err := options.CompleteUserWithSA(f, args, saNames, true); err != nil {
if err := options.CompleteUserWithSA(f, cmd, args, saNames, true, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.AddRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, true, "user", options.Targets, true, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, true, "user", options.Targets, true, options.DryRun, out)
}
},
}

cmd.Flags().StringVar(&options.RoleBindingName, "rolebinding-name", "", "Name of the rolebinding to modify or create. If left empty, appends to the first rolebinding found for the given role")
cmd.Flags().StringVar(&options.RoleNamespace, "role-namespace", "", "namespace where the role is located: empty means a role defined in cluster policy")
cmd.Flags().StringSliceVarP(&saNames, "serviceaccount", "z", saNames, "service account in the current namespace to use as a user")

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -116,20 +131,24 @@ func NewCmdRemoveRoleFromGroup(name, fullName string, f *clientcmd.Factory, out
Short: "Remove a role from groups for the current project",
Long: `Remove a role from groups for the current project`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(f, args, &options.Groups, "group", true); err != nil {
if err := options.Complete(f, cmd, args, &options.Groups, "group", true, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.RemoveRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, false, "group", options.Targets, true, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, false, "group", options.Targets, true, options.DryRun, out)
}
},
}

cmd.Flags().StringVar(&options.RoleNamespace, "role-namespace", "", "namespace where the role is located: empty means a role defined in cluster policy")

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -143,21 +162,25 @@ func NewCmdRemoveRoleFromUser(name, fullName string, f *clientcmd.Factory, out i
Short: "Remove a role from users for the current project",
Long: `Remove a role from users for the current project`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.CompleteUserWithSA(f, args, saNames, true); err != nil {
if err := options.CompleteUserWithSA(f, cmd, args, saNames, true, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.RemoveRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, false, "user", options.Targets, true, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, false, "user", options.Targets, true, options.DryRun, out)
}
},
}

cmd.Flags().StringVar(&options.RoleNamespace, "role-namespace", "", "namespace where the role is located: empty means a role defined in cluster policy")
cmd.Flags().StringSliceVarP(&saNames, "serviceaccount", "z", saNames, "service account in the current namespace to use as a user")

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -170,19 +193,23 @@ func NewCmdAddClusterRoleToGroup(name, fullName string, f *clientcmd.Factory, ou
Short: "Add a role to groups for all projects in the cluster",
Long: `Add a role to groups for all projects in the cluster`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(f, args, &options.Groups, "group", false); err != nil {
if err := options.Complete(f, cmd, args, &options.Groups, "group", false, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.AddRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, true, "group", options.Targets, false, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, true, "group", options.Targets, false, options.DryRun, out)
}
},
}

cmd.Flags().StringVar(&options.RoleBindingName, "rolebinding-name", "", "Name of the rolebinding to modify or create. If left empty, appends to the first rolebinding found for the given role")
kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -196,21 +223,25 @@ func NewCmdAddClusterRoleToUser(name, fullName string, f *clientcmd.Factory, out
Short: "Add a role to users for all projects in the cluster",
Long: `Add a role to users for all projects in the cluster`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.CompleteUserWithSA(f, args, saNames, false); err != nil {
if err := options.CompleteUserWithSA(f, cmd, args, saNames, false, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.AddRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, true, "user", options.Targets, false, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, true, "user", options.Targets, false, options.DryRun, out)
}
},
}

cmd.Flags().StringVar(&options.RoleBindingName, "rolebinding-name", "", "Name of the rolebinding to modify or create. If left empty, appends to the first rolebinding found for the given role")
cmd.Flags().StringSliceVarP(&saNames, "serviceaccount", "z", saNames, "service account in the current namespace to use as a user")

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -223,18 +254,22 @@ func NewCmdRemoveClusterRoleFromGroup(name, fullName string, f *clientcmd.Factor
Short: "Remove a role from groups for all projects in the cluster",
Long: `Remove a role from groups for all projects in the cluster`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(f, args, &options.Groups, "group", false); err != nil {
if err := options.Complete(f, cmd, args, &options.Groups, "group", false, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.RemoveRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, false, "group", options.Targets, false, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, false, "group", options.Targets, false, options.DryRun, out)
}
},
}

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

Expand All @@ -248,24 +283,28 @@ func NewCmdRemoveClusterRoleFromUser(name, fullName string, f *clientcmd.Factory
Short: "Remove a role from users for all projects in the cluster",
Long: `Remove a role from users for all projects in the cluster`,
Run: func(cmd *cobra.Command, args []string) {
if err := options.CompleteUserWithSA(f, args, saNames, false); err != nil {
if err := options.CompleteUserWithSA(f, cmd, args, saNames, false, out); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}

if err := options.RemoveRole(); err != nil {
kcmdutil.CheckErr(err)
return
}
printSuccessForCommand(options.RoleName, false, "user", options.Targets, false, out)
if len(options.Output) == 0 {
printSuccessForCommand(options.RoleName, false, "user", options.Targets, false, options.DryRun, out)
}
},
}

cmd.Flags().StringSliceVarP(&saNames, "serviceaccount", "z", saNames, "service account in the current namespace to use as a user")

kcmdutil.AddDryRunFlag(cmd)
kcmdutil.AddPrinterFlags(cmd)
return cmd
}

func (o *RoleModificationOptions) CompleteUserWithSA(f *clientcmd.Factory, args []string, saNames []string, isNamespaced bool) error {
func (o *RoleModificationOptions) CompleteUserWithSA(f *clientcmd.Factory, cmd *cobra.Command, args []string, saNames []string, isNamespaced bool, out io.Writer) error {
if len(args) < 1 {
return errors.New("you must specify a role")
}
Expand All @@ -286,6 +325,14 @@ func (o *RoleModificationOptions) CompleteUserWithSA(f *clientcmd.Factory, args
return err
}

mapper, _ := f.Object()

o.DryRun = kcmdutil.GetFlagBool(cmd, "dry-run")
o.Output = kcmdutil.GetFlagString(cmd, "output")
o.PrintObj = func(obj runtime.Object) error {
return f.PrintObject(cmd, false, mapper, obj, out)
}

roleBindingNamespace, _, err := f.DefaultNamespace()
if err != nil {
return err
Expand All @@ -305,7 +352,7 @@ func (o *RoleModificationOptions) CompleteUserWithSA(f *clientcmd.Factory, args
return nil
}

func (o *RoleModificationOptions) Complete(f *clientcmd.Factory, args []string, target *[]string, targetName string, isNamespaced bool) error {
func (o *RoleModificationOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, target *[]string, targetName string, isNamespaced bool, out io.Writer) error {
if len(args) < 2 {
return fmt.Errorf("you must specify at least two arguments: <role> <%s> [%s]...", targetName, targetName)
}
Expand All @@ -320,6 +367,14 @@ func (o *RoleModificationOptions) Complete(f *clientcmd.Factory, args []string,
return err
}

mapper, _ := f.Object()

o.DryRun = kcmdutil.GetFlagBool(cmd, "dry-run")
o.Output = kcmdutil.GetFlagString(cmd, "output")
o.PrintObj = func(obj runtime.Object) error {
return f.PrintObject(cmd, false, mapper, obj, out)
}

if isNamespaced {
roleBindingNamespace, _, err := f.DefaultNamespace()
if err != nil {
Expand Down Expand Up @@ -417,6 +472,14 @@ subjectCheck:
roleBinding.Subjects = append(roleBinding.Subjects, newSubject)
}

if len(o.Output) > 0 {
return o.PrintObj(roleBinding)
}

if o.DryRun {
return nil
}

if isUpdate {
err = o.RoleBindingAccessor.UpdateRoleBinding(roleBinding)
} else {
Expand All @@ -442,9 +505,29 @@ func (o *RoleModificationOptions) RemoveRole() error {
return fmt.Errorf("unable to locate RoleBinding for %v/%v", o.RoleNamespace, o.RoleName)
}

updatedBindings := &authorizationapi.RoleBindingList{
TypeMeta: metav1.TypeMeta{
Kind: "List",
APIVersion: "v1",
},
ListMeta: metav1.ListMeta{},
}

subjectsToRemove := authorizationapi.BuildSubjects(o.Users, o.Groups)
subjectsToRemove = append(subjectsToRemove, o.Subjects...)

if len(o.Output) > 0 {
for _, binding := range roleBindings {
binding.Subjects = removeSubjects(binding.Subjects, subjectsToRemove)
updatedBindings.Items = append(updatedBindings.Items, *binding)
}
return o.PrintObj(updatedBindings)
}

if o.DryRun {
return nil
}

for _, roleBinding := range roleBindings {
roleBinding.Subjects = removeSubjects(roleBinding.Subjects, subjectsToRemove)

Expand Down Expand Up @@ -478,7 +561,7 @@ existingLoop:
}

// prints affirmative output for role modification commands
func printSuccessForCommand(role string, didAdd bool, targetName string, targets []string, isNamespaced bool, out io.Writer) {
func printSuccessForCommand(role string, didAdd bool, targetName string, targets []string, isNamespaced bool, dryRun bool, out io.Writer) {
verb := "removed"
clusterScope := "cluster "
allTargets := fmt.Sprintf("%q", targets)
Expand All @@ -494,5 +577,10 @@ func printSuccessForCommand(role string, didAdd bool, targetName string, targets
verb = "added"
}

fmt.Fprintf(out, "%srole %q %s: %s\n", clusterScope, role, verb, allTargets)
msg := "%srole %q %s: %s"
if dryRun {
msg += " (dry run)"
}

fmt.Fprintf(out, msg+"\n", clusterScope, role, verb, allTargets)
}
Loading

0 comments on commit 846c827

Please sign in to comment.