1package bindingrulecreate 2 3import ( 4 "flag" 5 "fmt" 6 "strings" 7 8 "github.com/hashicorp/consul/api" 9 "github.com/hashicorp/consul/command/acl/bindingrule" 10 "github.com/hashicorp/consul/command/flags" 11 "github.com/mitchellh/cli" 12) 13 14func New(ui cli.Ui) *cmd { 15 c := &cmd{UI: ui} 16 c.init() 17 return c 18} 19 20type cmd struct { 21 UI cli.Ui 22 flags *flag.FlagSet 23 http *flags.HTTPFlags 24 help string 25 26 authMethodName string 27 description string 28 selector string 29 bindType string 30 bindName string 31 32 showMeta bool 33 format string 34} 35 36func (c *cmd) init() { 37 c.flags = flag.NewFlagSet("", flag.ContinueOnError) 38 39 c.flags.BoolVar( 40 &c.showMeta, 41 "meta", 42 false, 43 "Indicates that binding rule metadata such "+ 44 "as the raft indices should be shown for each entry.", 45 ) 46 47 c.flags.StringVar( 48 &c.authMethodName, 49 "method", 50 "", 51 "The auth method's name for which this binding rule applies. "+ 52 "This flag is required.", 53 ) 54 c.flags.StringVar( 55 &c.description, 56 "description", 57 "", 58 "A description of the binding rule.", 59 ) 60 c.flags.StringVar( 61 &c.selector, 62 "selector", 63 "", 64 "Selector is an expression that matches against verified identity "+ 65 "attributes returned from the auth method during login.", 66 ) 67 c.flags.StringVar( 68 &c.bindType, 69 "bind-type", 70 string(api.BindingRuleBindTypeService), 71 "Type of binding to perform (\"service\" or \"role\").", 72 ) 73 c.flags.StringVar( 74 &c.bindName, 75 "bind-name", 76 "", 77 "Name to bind on match. Can use ${var} interpolation. "+ 78 "This flag is required.", 79 ) 80 c.flags.StringVar( 81 &c.format, 82 "format", 83 bindingrule.PrettyFormat, 84 fmt.Sprintf("Output format {%s}", strings.Join(bindingrule.GetSupportedFormats(), "|")), 85 ) 86 87 c.http = &flags.HTTPFlags{} 88 flags.Merge(c.flags, c.http.ClientFlags()) 89 flags.Merge(c.flags, c.http.ServerFlags()) 90 flags.Merge(c.flags, c.http.NamespaceFlags()) 91 c.help = flags.Usage(help, c.flags) 92} 93 94func (c *cmd) Run(args []string) int { 95 if err := c.flags.Parse(args); err != nil { 96 return 1 97 } 98 99 if c.authMethodName == "" { 100 c.UI.Error(fmt.Sprintf("Missing required '-method' flag")) 101 c.UI.Error(c.Help()) 102 return 1 103 } else if c.bindType == "" { 104 c.UI.Error(fmt.Sprintf("Missing required '-bind-type' flag")) 105 c.UI.Error(c.Help()) 106 return 1 107 } else if c.bindName == "" { 108 c.UI.Error(fmt.Sprintf("Missing required '-bind-name' flag")) 109 c.UI.Error(c.Help()) 110 return 1 111 } 112 113 newRule := &api.ACLBindingRule{ 114 Description: c.description, 115 AuthMethod: c.authMethodName, 116 BindType: api.BindingRuleBindType(c.bindType), 117 BindName: c.bindName, 118 Selector: c.selector, 119 } 120 121 client, err := c.http.APIClient() 122 if err != nil { 123 c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) 124 return 1 125 } 126 127 rule, _, err := client.ACL().BindingRuleCreate(newRule, nil) 128 if err != nil { 129 c.UI.Error(fmt.Sprintf("Failed to create new binding rule: %v", err)) 130 return 1 131 } 132 133 formatter, err := bindingrule.NewFormatter(c.format, c.showMeta) 134 if err != nil { 135 c.UI.Error(err.Error()) 136 return 1 137 } 138 139 out, err := formatter.FormatBindingRule(rule) 140 if err != nil { 141 c.UI.Error(err.Error()) 142 return 1 143 } 144 if out != "" { 145 c.UI.Info(out) 146 } 147 148 return 0 149} 150 151func (c *cmd) Synopsis() string { 152 return synopsis 153} 154 155func (c *cmd) Help() string { 156 return flags.Usage(c.help, nil) 157} 158 159const synopsis = "Create an ACL binding rule" 160 161const help = ` 162Usage: consul acl binding-rule create [options] 163 164 Create a new binding rule: 165 166 $ consul acl binding-rule create \ 167 -method=minikube \ 168 -bind-type=service \ 169 -bind-name='k8s-${serviceaccount.name}' \ 170 -selector='serviceaccount.namespace==default and serviceaccount.name==web' 171` 172