-
Notifications
You must be signed in to change notification settings - Fork 5
/
multiforward.go
158 lines (128 loc) · 3.83 KB
/
multiforward.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package cmd
import (
"fmt"
"github.com/njnygaard/kubectl-multiforward/forward"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
var (
errGroupNotSpecified = "please specify a group found in your config (for you, one of these choices: \"%s\")"
errNoConfig = fmt.Errorf("no config is currently set, either ~/.multiforward.yaml or ./.multiforward.yaml")
errMalformedConfig = fmt.Errorf("could not unmarshal config found in either ~/.multiforward.yaml or ./.multiforward.yaml")
errUnspecified = fmt.Errorf("something went wrong. do you have your config file in ~/.multiforward.yaml or ./.multiforward.yaml")
)
type Config struct {
Groups []Group
}
type Group struct {
Name string
Services []Service
}
type Service struct {
DisplayName string
Port uint
Namespace string
Name string
Protocol string
}
// NewCmdNamespace provides a cobra command wrapping NamespaceOptions
func NewCmdNamespace(streams genericclioptions.IOStreams) *cobra.Command {
// o := NewNamespaceOptions(streams)
cmd := &cobra.Command{
Use: "multiforward <group>",
Short: "forward to services specified in ~/.multiforward.yaml or .multiforward.yaml",
Long: `
An example format for your local config file (~/.multiforward.yaml or .multiforward.yaml) can be found here: https://github.com/njnygaard/kubectl-multiforward/blob/master/.multiforward.example.yaml
Or you can reference the following YAML structure where 'displayName' is a human-readable handle and 'name' and 'namespace' identify the Kubernetes resource.
groups:
- name: production
services:
- displayName: Alertmanager
port: 9093
namespace: monitoring-prometheus
name: alertmanager-operated
protocol: http
- displayName: Prometheus
port: 9090
namespace: monitoring-prometheus
name: prometheus-operated
protocol: http
- name: staging
services:
- displayName: Elasticsearch
port: 9200
namespace: monitoring-eck
name: elasticsearch-es-http
protocol: https
`,
Example: "kubectl multiforward [group]",
SilenceUsage: true,
RunE: func(c *cobra.Command, args []string) (err error) {
var config Config
err = Configure()
if err != nil {
return errNoConfig
}
err = viper.Unmarshal(&config)
if err != nil {
return errMalformedConfig
}
var groupNames string
for i, v := range config.Groups {
if i == 0 {
groupNames = v.Name
continue
}
groupNames += ", " + v.Name
}
if len(args) == 0 || args[0] == "" {
c.Help()
fmt.Println()
return fmt.Errorf(errGroupNotSpecified, groupNames)
}
var found bool
for _, v := range config.Groups {
if v.Name == args[0] {
found = true
}
}
if !found {
return fmt.Errorf(errGroupNotSpecified, groupNames)
}
var serviceGroup []Service
for _, v := range config.Groups {
if v.Name == args[0] {
serviceGroup = v.Services
}
}
var serviceMapping = map[string]forward.ServiceMapping{}
for _, v := range serviceGroup {
var mapping forward.ServiceMapping
mapping.Identifier = v.Name
mapping.Namespace = v.Namespace
mapping.Port = int(v.Port)
mapping.Protocol = v.Protocol
serviceMapping[v.DisplayName] = mapping
}
forward.Forward(serviceMapping)
return nil
},
}
cmd.Flags().BoolP("help", "h", false, fmt.Sprintf("help for %s, contains config locations and sample configuration", cmd.Name()))
return cmd
}
func Configure() (err error) {
viper.SetConfigName(".multiforward")
viper.SetConfigType("yaml")
viper.AddConfigPath("$HOME")
viper.AddConfigPath(".")
if err = viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
return errNoConfig
} else {
return errUnspecified
}
}
return
}