Skip to content

Commit 2588092

Browse files
committed
Implement templating
1 parent a2f1946 commit 2588092

File tree

2 files changed

+126
-45
lines changed

2 files changed

+126
-45
lines changed

README.md

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ The format is quite evident. Just few remarks:
6565
* The parameter *state=absent* can be used for deleting topics and ACLs if they present. Any value other than *absent* is considered as *present*
6666
* The *patternType=MATCH*, *patternType=ANY*, *operation=ANY*, *principal=** can be used when *state=absent* for deleting ACLs but be careful with that
6767
* The ACL operation is described as *OperationType:Host*
68-
* The Host part can be omitted and will be considered as '*' when *state=present* and as any host (including '*' itself and any separately defined IP) when *state=absent*
68+
* The Host part can be omitted and will be considered as '*' when *state=present* and as any host (including '*' itself and any separately defined IP) when *state=absent*
6969
7070
kafka-cluster-example2.json:
7171
```json
@@ -182,42 +182,77 @@ Kafka-Ops can also export the current topics and ACLs from the cluster. This can
182182
Note that if no broker is defined then Kafka-Ops tries to connect to *localhost:9092*.
183183

184184

185+
## Templating
186+
187+
Kafka-Ops supports the simple templating for Spec-file. For now the variables are only read from environment variables and from command-line arguments.
188+
189+
Templating can be useful for multi-tenant and multi-environment Kafka clusters.
190+
191+
kafka-cluster-example3.yaml
192+
```yaml
193+
---
194+
topics:
195+
- configs:
196+
cleanup.policy: compact
197+
name: my-product.{{ .Plant }}.{{ .Env }}.my-topic
198+
partitions: 2
199+
```
200+
201+
This spec can by then applied:
202+
203+
```
204+
Plant=myplant Env=myenv ./kafka-ops --apply --spec kafka-cluster-example3.yaml --template --var Env=realenv --var One=more
205+
206+
TASK [TOPIC : Create topic my-product.myplant.realenv.my-topic (partitions=2, replicas=1)] ****************
207+
changed: [cy-selenium.quotix.io:9092]
208+
209+
SUMMARY ********************************************************************************
210+
ok=0 changed=1 failed=0
211+
```
212+
213+
The value defined in command-line argument takes precedence over the one from environment variable.
214+
215+
185216
## Full Usage
186217

187218
```
188219
./kafka-ops --help
189220
Manage Kafka cluster resources (topics and ACLs)
190221
Usage: ./kafka-ops <action> [<options>] [<broker connection options>]
191-
----------------
192-
Actions
193-
--help Show this help and exit
194-
--dump Dump cluster resources and their configs to stdout
195-
See also --json and --yaml options
196-
--apply Idempotently align cluster resources with the spec manifest
197-
See also --spec, --json and --yaml options
198-
----------------
199-
Options
200-
--spec A path to manifest (specification file) to be used
201-
with --apply action
202-
Can be also set by Env variable KAFKA_SPEC_FILE
203-
--yaml Spec-file is in YAML format
204-
Will try to detect format if none of --yaml or --json is set
205-
--json Spec-file is in JSON format
206-
Will try to detect format if none of --yaml or --json is set
207-
--verbose Verbose output
208-
--stop-on-error Exit on first occurred error
209-
----------------
210-
Broker connection options
211-
--broker Bootstrap-brokers, comma-separated. Default is localhost:9092
212-
Can be also set by Env variable KAFKA_BROKER
213-
--protocol Security protocol. Default is plaintext
214-
Available options: plaintext, sasl_ssl, sasl_plaintext
215-
--mechanism SASL mechanism. Default is scram-sha-256
216-
Available options: scram-sha-256, scram-sha-512
217-
--username Username for authentication
218-
Can be also set by Env variable KAFKA_USERNAME
219-
--password Password for authentication
220-
Can be also set by Env variable KAFKA_PASSWORD
222+
----------------
223+
Actions
224+
--help Show this help and exit
225+
--dump Dump cluster resources and their configs to stdout
226+
See also --json and --yaml options
227+
--apply Idempotently align cluster resources with the spec manifest
228+
See also --spec, --json and --yaml options
229+
----------------
230+
Options
231+
--spec A path to manifest (specification file) to be used
232+
with --apply action
233+
Can be also set by Env variable KAFKA_SPEC_FILE
234+
--yaml Spec-file is in YAML format
235+
Will try to detect format if none of --yaml or --json is set
236+
--json Spec-file is in JSON format
237+
Will try to detect format if none of --yaml or --json is set
238+
--template Spec-file is a Go-template to be parsed. The values are read from
239+
Env variables and from --var arguments (--var arguments are
240+
taking precedence)
241+
--var Variable in format "key=value". Can be presented multiple times
242+
--verbose Verbose output
243+
--stop-on-error Exit on first occurred error
244+
----------------
245+
Broker connection options
246+
--broker Bootstrap-brokers, comma-separated. Default is localhost:9092
247+
Can be also set by Env variable KAFKA_BROKER
248+
--protocol Security protocol. Default is plaintext
249+
Available options: plaintext, sasl_ssl, sasl_plaintext
250+
--mechanism SASL mechanism. Default is scram-sha-256
251+
Available options: scram-sha-256, scram-sha-512
252+
--username Username for authentication
253+
Can be also set by Env variable KAFKA_USERNAME
254+
--password Password for authentication
255+
Can be also set by Env variable KAFKA_PASSWORD
221256
```
222257

223258
## How to build the binary

kafka-ops.go

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"encoding/json"
1414
"errors"
1515
"crypto/tls"
16+
"text/template"
17+
"bytes"
1618
)
1719

1820
var (
@@ -29,8 +31,12 @@ var (
2931
actionDump bool
3032
actionHelp bool
3133
errorStop bool
34+
isTemplate bool
35+
varFlags arrFlags
3236
)
3337

38+
type arrFlags []string
39+
3440
type Spec struct {
3541
Topics []Topic `yaml:"topics" json:"topics"`
3642
Acls []Acl `yaml:"acls" json:"acls"`
@@ -93,7 +99,9 @@ func init() {
9399
flag.BoolVar(&isYAML, "yaml", false, "Spec-file is in YAML format (will try to detect format if none of --yaml or --json is set)")
94100
flag.BoolVar(&isJSON, "json", false, "Spec-file is in JSON format (will try to detect format if none of --yaml or --json is set)")
95101
flag.BoolVar(&errorStop, "stop-on-error", false, "Exit on first occurred error")
102+
flag.BoolVar(&isTemplate, "template", false, "Spec-file is a template")
96103
flag.BoolVar(&verbose, "verbose", false, "Verbose output")
104+
flag.Var(&varFlags, "var", "Variable for templating")
97105
flag.Usage = func() {
98106
usage()
99107
}
@@ -583,13 +591,27 @@ func aclExists(admin *sarama.ClusterAdmin, acls *[]sarama.ResourceAcls, acl Sing
583591
return false
584592
}
585593

586-
func parseSpecFile() (Spec,error) {
594+
func parseSpecFile() (Spec, error) {
587595
var spec Spec
588596
specFile, err := ioutil.ReadFile(specfile)
589597
if err != nil {
590598
return spec, err
591599
}
592600

601+
if isTemplate {
602+
t, err := template.New("").Option("missingkey=error").Parse(string(specFile))
603+
if err != nil {
604+
return spec, err
605+
}
606+
config := loadEnvMap()
607+
var tpl bytes.Buffer
608+
err = t.Execute(&tpl, config)
609+
if err != nil {
610+
return spec, err
611+
}
612+
specFile = tpl.Bytes()
613+
}
614+
593615
if (isYAML) {
594616
err = yaml.Unmarshal(specFile, &spec)
595617
} else if (isJSON) {
@@ -688,10 +710,30 @@ func loadEnvVar(key string) string {
688710
return ""
689711
}
690712

713+
func loadEnvMap() map[string]string {
714+
items := make(map[string]string)
715+
for _, item := range append(os.Environ(), varFlags...) {
716+
splits := strings.Split(item, "=")
717+
key := splits[0]
718+
val := strings.Join(splits[1:], "=")
719+
items[key] = val
720+
}
721+
return items
722+
}
723+
691724
func getPtr(s string) *string {
692725
return &s
693726
}
694727

728+
func (f *arrFlags) Set(s string) error {
729+
*f = append(*f, s)
730+
return nil
731+
}
732+
733+
func (f *arrFlags) String() string {
734+
return "-"
735+
}
736+
695737
func aclOperationToString(operation sarama.AclOperation) string {
696738
switch operation {
697739
case sarama.AclOperationAny:
@@ -846,38 +888,42 @@ func aclPermissionTypeFromString(permissionType string) sarama.AclPermissionType
846888

847889
func usage() {
848890
usage := `Manage Kafka cluster resources (topics and ACLs)
849-
Usage: %s <action> [<options>] [<broker connection options>]
891+
Usage: %s <action> [<options>] [<broker connection options>]
850892
----------------
851893
Actions
852894
--help Show this help and exit
853895
--dump Dump cluster resources and their configs to stdout
854-
See also --json and --yaml options
896+
See also --json and --yaml options
855897
--apply Idempotently align cluster resources with the spec manifest
856-
See also --spec, --json and --yaml options
898+
See also --spec, --json and --yaml options
857899
----------------
858900
Options
859901
--spec A path to manifest (specification file) to be used
860-
with --apply action
861-
Can be also set by Env variable KAFKA_SPEC_FILE
902+
with --apply action
903+
Can be also set by Env variable KAFKA_SPEC_FILE
862904
--yaml Spec-file is in YAML format
863-
Will try to detect format if none of --yaml or --json is set
905+
Will try to detect format if none of --yaml or --json is set
864906
--json Spec-file is in JSON format
865-
Will try to detect format if none of --yaml or --json is set
907+
Will try to detect format if none of --yaml or --json is set
908+
--template Spec-file is a Go-template to be parsed. The values are read from
909+
Env variables and from --var arguments (--var arguments are
910+
taking precedence)
911+
--var Variable in format "key=value". Can be presented multiple times
866912
--verbose Verbose output
867913
--stop-on-error Exit on first occurred error
868914
----------------
869915
Broker connection options
870916
--broker Bootstrap-brokers, comma-separated. Default is localhost:9092
871-
Can be also set by Env variable KAFKA_BROKER
917+
Can be also set by Env variable KAFKA_BROKER
872918
--protocol Security protocol. Default is plaintext
873-
Available options: plaintext, sasl_ssl, sasl_plaintext
919+
Available options: plaintext, sasl_ssl, sasl_plaintext
874920
--mechanism SASL mechanism. Default is scram-sha-256
875-
Available options: scram-sha-256, scram-sha-512
921+
Available options: scram-sha-256, scram-sha-512
876922
--username Username for authentication
877-
Can be also set by Env variable KAFKA_USERNAME
923+
Can be also set by Env variable KAFKA_USERNAME
878924
--password Password for authentication
879-
Can be also set by Env variable KAFKA_PASSWORD
880-
`
925+
Can be also set by Env variable KAFKA_PASSWORD
926+
`
881927

882928
fmt.Fprintf(os.Stderr, usage, os.Args[0])
883929
//flag.PrintDefaults()

0 commit comments

Comments
 (0)