Skip to content

Commit 1d387ce

Browse files
matrix-tools: refactor subcommands
1 parent 636f988 commit 1d387ce

18 files changed

Lines changed: 559 additions & 324 deletions

File tree

matrix-tools/cmd/main.go

Lines changed: 10 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,16 @@ package main
66

77
import (
88
"fmt"
9-
"io"
109
"os"
1110

12-
"flag"
13-
11+
deploymentmarkers "github.com/element-hq/ess-helm/matrix-tools/internal/cmd/deployment-markers"
12+
generatesecrets "github.com/element-hq/ess-helm/matrix-tools/internal/cmd/generate-secrets"
13+
renderconfig "github.com/element-hq/ess-helm/matrix-tools/internal/cmd/render-config"
14+
"github.com/element-hq/ess-helm/matrix-tools/internal/cmd/syn2mas"
15+
"github.com/element-hq/ess-helm/matrix-tools/internal/cmd/tcpwait"
1416
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/args"
15-
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/marker"
16-
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/renderer"
17-
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/secret"
18-
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/syn2mas"
19-
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/tcpwait"
20-
"github.com/pkg/errors"
21-
"gopkg.in/yaml.v3"
22-
"k8s.io/client-go/kubernetes"
23-
"k8s.io/client-go/rest"
2417
)
2518

26-
func getKubernetesClient() (kubernetes.Interface, error) {
27-
config, err := rest.InClusterConfig()
28-
if err != nil {
29-
return nil, err
30-
}
31-
clientset, err := kubernetes.NewForConfig(config)
32-
if err != nil {
33-
return nil, err
34-
}
35-
return clientset, nil
36-
}
37-
38-
func readFiles(paths []string) ([]io.Reader, []func() error, error) {
39-
files := make([]io.Reader, 0)
40-
closeFiles := make([]func() error, 0)
41-
for _, path := range paths {
42-
fileReader, err := os.Open(path)
43-
if err != nil {
44-
return files, closeFiles, fmt.Errorf("failed to open file: %w", err)
45-
}
46-
files = append(files, fileReader)
47-
closeFiles = append(closeFiles, fileReader.Close)
48-
}
49-
return files, closeFiles, nil
50-
}
5119

5220
func main() {
5321
options, err := args.ParseArgs(os.Args)
@@ -58,97 +26,15 @@ func main() {
5826

5927
switch options.Command {
6028
case args.RenderConfig:
61-
fileReaders, closeFiles, err := readFiles(options.Files)
62-
defer func() {
63-
for _, closeFn := range closeFiles {
64-
err := closeFn()
65-
if err != nil {
66-
fmt.Println("Error closing file : ", err)
67-
}
68-
}
69-
}()
70-
if err != nil {
71-
fmt.Println(err)
72-
os.Exit(1)
73-
}
74-
result, err := renderer.RenderConfig(fileReaders)
75-
if err != nil {
76-
if err == flag.ErrHelp {
77-
flag.CommandLine.Usage()
78-
} else {
79-
fmt.Println("Error:", err)
80-
}
81-
os.Exit(1)
82-
}
83-
var outputYAML []byte
84-
if outputYAML, err = yaml.Marshal(result); err != nil {
85-
fmt.Println("Error marshalling merged config to YAML:", err)
86-
os.Exit(1)
87-
}
88-
89-
fmt.Printf("Rendering config to file: %v\n", options.Output)
90-
if os.Getenv("DEBUG_RENDERING") == "1" {
91-
fmt.Println(string(outputYAML))
92-
}
93-
err = os.WriteFile(options.Output, outputYAML, 0440)
94-
if err != nil {
95-
fmt.Println("Error writing to file:", err)
96-
os.Exit(1)
97-
}
29+
renderconfig.Run(options.RenderConfig)
9830
case args.TCPWait:
99-
tcpwait.WaitForTCP(options.Address)
31+
tcpwait.Run(options.TcpWait)
10032
case args.Syn2Mas:
101-
clientset, err := getKubernetesClient()
102-
if err != nil {
103-
fmt.Println("Error getting Kubernetes client: ", err)
104-
os.Exit(1)
105-
}
106-
namespace := os.Getenv("NAMESPACE")
107-
if namespace == "" {
108-
fmt.Println("Error, $NAMESPACE is not defined")
109-
os.Exit(1)
110-
}
111-
syn2mas.RunSyn2MAS(clientset, namespace, options.SynapseConfig, options.MASConfig)
33+
syn2mas.Run(options.Syn2Mas)
11234
case args.GenerateSecrets:
113-
clientset, err := getKubernetesClient()
114-
if err != nil {
115-
fmt.Println("Error getting Kubernetes client: ", err)
116-
os.Exit(1)
117-
}
118-
namespace := os.Getenv("NAMESPACE")
119-
if namespace == "" {
120-
fmt.Println("Error, $NAMESPACE is not defined")
121-
os.Exit(1)
122-
}
123-
124-
for _, generatedSecret := range options.GeneratedSecrets {
125-
err := secret.GenerateSecret(clientset, options.Labels, namespace, generatedSecret.Name, generatedSecret.Key, generatedSecret.Type)
126-
if err != nil {
127-
wrappedErr := errors.Wrapf(err, "error generating secret: %s", generatedSecret.ArgValue)
128-
fmt.Println("Error:", wrappedErr)
129-
os.Exit(1)
130-
}
131-
}
35+
generatesecrets.Run(options.GenerateSecrets)
13236
case args.DeploymentMarkers:
133-
clientset, err := getKubernetesClient()
134-
if err != nil {
135-
fmt.Println("Error getting Kubernetes client: ", err)
136-
os.Exit(1)
137-
}
138-
namespace := os.Getenv("NAMESPACE")
139-
if namespace == "" {
140-
fmt.Println("Error, $NAMESPACE is not defined")
141-
os.Exit(1)
142-
}
143-
144-
for _, depMarker := range options.DeploymentMarkers {
145-
err := marker.GenerateConfigMap(clientset, options.Labels, namespace, depMarker.Name, depMarker.Key, depMarker.Step, depMarker.NewValue, depMarker.AllowedValues)
146-
if err != nil {
147-
wrappedErr := errors.Wrapf(err, "error generating configmap: %v", depMarker)
148-
fmt.Println("Error:", wrappedErr)
149-
os.Exit(1)
150-
}
151-
}
37+
deploymentmarkers.Run(options.DeploymentMarkers)
15238
default:
15339
fmt.Printf("Unknown command")
15440
os.Exit(1)

matrix-tools/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ require (
3333
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
3434
github.com/modern-go/reflect2 v1.0.2 // indirect
3535
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
36+
github.com/pmezard/go-difflib v1.0.0 // indirect
37+
github.com/stretchr/testify v1.10.0 // indirect
3638
github.com/x448/float16 v0.8.4 // indirect
3739
golang.org/x/net v0.38.0 // indirect
3840
golang.org/x/oauth2 v0.27.0 // indirect
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package deploymentmarkers
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"strings"
7+
)
8+
9+
const (
10+
FlagSetName = "deployment-markers"
11+
)
12+
13+
type DeploymentMarkersOptions struct {
14+
Labels map[string]string
15+
DeploymentMarkers []DeploymentMarker
16+
}
17+
18+
19+
type DeploymentMarker struct {
20+
Name string
21+
Key string
22+
Step string
23+
NewValue string
24+
AllowedValues []string
25+
}
26+
27+
func ParseArgs(args []string) (*DeploymentMarkersOptions, error) {
28+
options := &DeploymentMarkersOptions{}
29+
30+
deploymentMarkersSet := flag.NewFlagSet(FlagSetName, flag.ExitOnError)
31+
deploymentMarkers := deploymentMarkersSet.String("markers", "", "Comma-separated list of deployment markers, with Semi-colon separated list of previous allowed values in the format of `name:step:newValue:[allowedValues;..]`")
32+
labels := deploymentMarkersSet.String("labels", "", "Comma-separated list of labels for generated secrets, in the format of `key=value`")
33+
step := deploymentMarkersSet.String("step", "", "One of `pre` or `post`")
34+
35+
err := deploymentMarkersSet.Parse(args)
36+
if err != nil {
37+
return nil, err
38+
}
39+
for _, deploymentMarkerArg := range strings.Split(*deploymentMarkers, ",") {
40+
parsedValue := strings.Split(deploymentMarkerArg, ":")
41+
if len(parsedValue) < 3 {
42+
return nil, fmt.Errorf("invalid deployment marker format, expect <name:key:newValue:[allowedValues;..]>: %s", deploymentMarkerArg)
43+
}
44+
parsedAllowedValues := strings.Split(parsedValue[3], ";")
45+
deploymentMarker := DeploymentMarker{Name: parsedValue[0], Key: parsedValue[1], Step: *step, NewValue: parsedValue[2], AllowedValues: parsedAllowedValues}
46+
options.DeploymentMarkers = append(options.DeploymentMarkers, deploymentMarker)
47+
}
48+
options.Labels = make(map[string]string)
49+
if *labels != "" {
50+
for _, label := range strings.Split(*labels, ",") {
51+
parsedLabelValue := strings.Split(label, "=")
52+
options.Labels[parsedLabelValue[0]] = parsedLabelValue[1]
53+
}
54+
}
55+
options.Labels["app.kubernetes.io/managed-by"] = "matrix-tools-deployment-markers"
56+
return options, nil
57+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package deploymentmarkers
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/marker"
8+
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/util"
9+
"github.com/pkg/errors"
10+
)
11+
12+
func Run(options *DeploymentMarkersOptions) {
13+
clientset, err := util.GetKubernetesClient()
14+
if err != nil {
15+
fmt.Println("Error getting Kubernetes client: ", err)
16+
os.Exit(1)
17+
}
18+
namespace := os.Getenv("NAMESPACE")
19+
if namespace == "" {
20+
fmt.Println("Error, $NAMESPACE is not defined")
21+
os.Exit(1)
22+
}
23+
24+
for _, depMarker := range options.DeploymentMarkers {
25+
err := marker.GenerateConfigMap(clientset, options.Labels, namespace, depMarker.Name, depMarker.Key, depMarker.Step, depMarker.NewValue, depMarker.AllowedValues)
26+
if err != nil {
27+
wrappedErr := errors.Wrapf(err, "error generating configmap: %v", depMarker)
28+
fmt.Println("Error:", wrappedErr)
29+
os.Exit(1)
30+
}
31+
}
32+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package generatesecrets
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/secret"
9+
)
10+
11+
const (
12+
FlagSetName = "generate-secrets"
13+
)
14+
15+
type GenerateSecretsOptions struct {
16+
GeneratedSecrets []GeneratedSecret
17+
Labels map[string]string
18+
}
19+
20+
type GeneratedSecret struct {
21+
ArgValue string
22+
Name string
23+
Key string
24+
Type secret.SecretType
25+
}
26+
27+
func parseSecretType(value string) (secret.SecretType, error) {
28+
switch value {
29+
case "rand32":
30+
return secret.Rand32, nil
31+
case "signingkey":
32+
return secret.SigningKey, nil
33+
case "hex32":
34+
return secret.Hex32, nil
35+
case "rsa":
36+
return secret.RSA, nil
37+
case "ecdsaprime256v1":
38+
return secret.EcdsaPrime256v1, nil
39+
case "ecdsasecp256k1":
40+
return secret.EcdsaSecp256k1, nil
41+
default:
42+
return secret.UnknownSecretType, fmt.Errorf("unknown secret type: %s", value)
43+
}
44+
}
45+
46+
47+
func ParseArgs(args []string) (*GenerateSecretsOptions, error) {
48+
var options GenerateSecretsOptions
49+
50+
generateSecretsSet := flag.NewFlagSet("generate-secrets", flag.ExitOnError)
51+
secrets := generateSecretsSet.String("secrets", "", "Comma-separated list of secrets to generate, in the format of `name:key:type`, where `type` is one of: rand32")
52+
secretsLabels := generateSecretsSet.String("labels", "", "Comma-separated list of labels for generated secrets, in the format of `key=value`")
53+
54+
err := generateSecretsSet.Parse(args)
55+
if err != nil {
56+
return nil, err
57+
}
58+
for _, generatedSecretArg := range strings.Split(*secrets, ",") {
59+
parsedValue := strings.Split(generatedSecretArg, ":")
60+
if len(parsedValue) < 3 {
61+
return nil, fmt.Errorf("invalid generated secret format, expect <name:key:type:...>: %s", generatedSecretArg)
62+
}
63+
var parsedSecretType secret.SecretType
64+
if parsedSecretType, err = parseSecretType(parsedValue[2]); err != nil {
65+
return nil, fmt.Errorf("invalid secret type in %s : %v", generatedSecretArg, err)
66+
}
67+
68+
generatedSecret := GeneratedSecret{ArgValue: generatedSecretArg, Name: parsedValue[0], Key: parsedValue[1], Type: parsedSecretType}
69+
options.GeneratedSecrets = append(options.GeneratedSecrets, generatedSecret)
70+
}
71+
options.Labels = make(map[string]string)
72+
if *secretsLabels != "" {
73+
for _, label := range strings.Split(*secretsLabels, ",") {
74+
parsedLabelValue := strings.Split(label, "=")
75+
options.Labels[parsedLabelValue[0]] = parsedLabelValue[1]
76+
}
77+
}
78+
options.Labels["app.kubernetes.io/managed-by"] = "matrix-tools-init-secrets"
79+
return &options, nil
80+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package generatesecrets
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/secret"
8+
"github.com/element-hq/ess-helm/matrix-tools/internal/pkg/util"
9+
"github.com/pkg/errors"
10+
)
11+
12+
func Run(options *GenerateSecretsOptions) {
13+
clientset, err := util.GetKubernetesClient()
14+
if err != nil {
15+
fmt.Println("Error getting Kubernetes client: ", err)
16+
os.Exit(1)
17+
}
18+
namespace := os.Getenv("NAMESPACE")
19+
if namespace == "" {
20+
fmt.Println("Error, $NAMESPACE is not defined")
21+
os.Exit(1)
22+
}
23+
24+
for _, generatedSecret := range options.GeneratedSecrets {
25+
err := secret.GenerateSecret(clientset, options.Labels, namespace, generatedSecret.Name, generatedSecret.Key, generatedSecret.Type)
26+
if err != nil {
27+
wrappedErr := errors.Wrapf(err, "error generating secret: %s", generatedSecret.ArgValue)
28+
fmt.Println("Error:", wrappedErr)
29+
os.Exit(1)
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)