5
5
"fmt"
6
6
"net/http"
7
7
"os"
8
+ "strconv"
9
+ "strings"
8
10
"text/tabwriter"
9
11
10
12
"github.com/spf13/pflag"
@@ -15,35 +17,164 @@ import (
15
17
16
18
type urlsCmd struct {}
17
19
20
+ // DevURL is the parsed json response record for a devURL from cemanager
18
21
type DevURL struct {
22
+ ID string `json:"id"`
19
23
URL string `json:"url"`
20
24
Port string `json:"port"`
21
25
Access string `json:"access"`
22
26
}
23
27
24
- func (cmd urlsCmd )Spec () cli.CommandSpec {
28
+ var urlAccessLevel = map [string ]string {
29
+ //Remote API endpoint requires these in uppercase
30
+ "PRIVATE" :"Only you can access" ,
31
+ "ORG" :"All members of your organization can access" ,
32
+ "AUTHED" :"Authenticated users can access" ,
33
+ "PUBLIC" :"Anyone on the internet can access this link" ,
34
+ }
35
+
36
+ func portIsValid (port string )bool {
37
+ p ,err := strconv .ParseUint (port ,10 ,16 )
38
+ if p < 1 {
39
+ // port 0 means 'any free port', which we don't support
40
+ err = strconv .ErrRange
41
+ }
42
+ if err != nil {
43
+ fmt .Println ("Invalid port" )
44
+ }
45
+ return err == nil
46
+ }
47
+
48
+ func accessLevelIsValid (level string )bool {
49
+ _ ,ok := urlAccessLevel [level ]
50
+ if ! ok {
51
+ fmt .Println ("Invalid access level" )
52
+ }
53
+ return ok
54
+ }
55
+
56
+ type createSubCmd struct {
57
+ access string
58
+ }
59
+
60
+ func (sub * createSubCmd )RegisterFlags (fl * pflag.FlagSet ) {
61
+ fl .StringVarP (& sub .access ,"access" ,"a" ,"private" ,"[private | org | authed | public] set devurl access" )
62
+ }
63
+
64
+ func (sub createSubCmd )Spec () cli.CommandSpec {
25
65
return cli.CommandSpec {
26
- Name :"urls " ,
27
- Usage :"<env name>" ,
28
- Desc :"get all development urls for external access" ,
66
+ Name :"create " ,
67
+ Usage :"<env name> <port> [--access <level>] " ,
68
+ Desc :"create/update a devurl for external access" ,
29
69
}
30
70
}
31
71
32
- func (cmd urlsCmd )Run (fl * pflag.FlagSet ) {
33
- var envName = fl .Arg (0 )
72
+ // Run creates or updates a devURL, specified by env ID and port
73
+ // (fl.Arg(0) and fl.Arg(1)), with access level (fl.Arg(2)) on
74
+ // the cemanager.
75
+ func (sub createSubCmd )Run (fl * pflag.FlagSet ) {
76
+ envName := fl .Arg (0 )
77
+ port := fl .Arg (1 )
78
+ access := fl .Arg (2 )
34
79
35
80
if envName == "" {
36
81
exitUsage (fl )
37
82
}
38
83
84
+ if ! portIsValid (port ) {
85
+ exitUsage (fl )
86
+ }
87
+
88
+ access = strings .ToUpper (sub .access )
89
+ if ! accessLevelIsValid (access ) {
90
+ exitUsage (fl )
91
+ }
92
+
39
93
entClient := requireAuth ()
40
94
41
95
env := findEnv (entClient ,envName )
42
96
97
+ _ ,found := devURLID (port ,urlList (envName ))
98
+ if found {
99
+ fmt .Printf ("Updating devurl for port %v\n " ,port )
100
+ }else {
101
+ fmt .Printf ("Adding devurl for port %v\n " ,port )
102
+ }
103
+
104
+ err := entClient .UpsertDevURL (env .ID ,port ,access )
105
+ if err != nil {
106
+ flog .Error ("upsert devurl: %s" ,err .Error ())
107
+ }
108
+ }
109
+
110
+ type delSubCmd struct {}
111
+
112
+ func (sub delSubCmd )Spec () cli.CommandSpec {
113
+ return cli.CommandSpec {
114
+ Name :"del" ,
115
+ Usage :"<env name> <port>" ,
116
+ Desc :"delete a devurl" ,
117
+ }
118
+ }
119
+
120
+ // devURLID returns the ID of a devURL, given the env name and port.
121
+ // ("", false) is returned if no match is found.
122
+ func devURLID (port string ,urls []DevURL ) (string ,bool ) {
123
+ for _ ,url := range urls {
124
+ if url .Port == port {
125
+ return url .ID ,true
126
+ }
127
+ }
128
+ return "" ,false
129
+ }
130
+
131
+ // Run deletes a devURL, specified by env ID and port, from the cemanager.
132
+ func (sub delSubCmd )Run (fl * pflag.FlagSet ) {
133
+ envName := fl .Arg (0 )
134
+ port := fl .Arg (1 )
135
+
136
+ if envName == "" {
137
+ exitUsage (fl )
138
+ }
139
+
140
+ if ! portIsValid (port ) {
141
+ exitUsage (fl )
142
+ }
143
+
144
+ entClient := requireAuth ()
145
+
146
+ env := findEnv (entClient ,envName )
147
+
148
+ urlID ,found := devURLID (port ,urlList (envName ))
149
+ if found {
150
+ fmt .Printf ("Deleting devurl for port %v\n " ,port )
151
+ }else {
152
+ flog .Fatal ("No devurl found for port %v" ,port )
153
+ }
154
+
155
+ err := entClient .DelDevURL (env .ID ,urlID )
156
+ if err != nil {
157
+ flog .Error ("delete devurl: %s" ,err .Error ())
158
+ }
159
+ }
160
+
161
+ func (cmd urlsCmd )Spec () cli.CommandSpec {
162
+ return cli.CommandSpec {
163
+ Name :"urls" ,
164
+ Usage :"<env name>" ,
165
+ Desc :"get all development urls for external access" ,
166
+ }
167
+ }
168
+
169
+ // urlList returns the list of active devURLs from the cemanager.
170
+ func urlList (envName string ) []DevURL {
171
+ entClient := requireAuth ()
172
+ env := findEnv (entClient ,envName )
173
+
43
174
reqString := "%s/api/environments/%s/devurls?session_token=%s"
44
- reqUrl := fmt .Sprintf (reqString ,entClient .BaseURL ,env .ID ,entClient .Token )
175
+ reqURL := fmt .Sprintf (reqString ,entClient .BaseURL ,env .ID ,entClient .Token )
45
176
46
- resp ,err := http .Get (reqUrl )
177
+ resp ,err := http .Get (reqURL )
47
178
if err != nil {
48
179
flog .Fatal ("%v" ,err )
49
180
}
@@ -55,7 +186,7 @@ func (cmd urlsCmd) Run(fl *pflag.FlagSet) {
55
186
56
187
dec := json .NewDecoder (resp .Body )
57
188
58
- var devURLs = make ([]DevURL ,0 )
189
+ devURLs : =make ([]DevURL ,0 )
59
190
err = dec .Decode (& devURLs )
60
191
if err != nil {
61
192
flog .Fatal ("%v" ,err )
@@ -65,9 +196,25 @@ func (cmd urlsCmd) Run(fl *pflag.FlagSet) {
65
196
fmt .Printf ("no dev urls were found for environment: %s\n " ,envName )
66
197
}
67
198
199
+ return devURLs
200
+ }
201
+
202
+ // Run gets the list of active devURLs from the cemanager for the
203
+ // specified environment and outputs info to stdout.
204
+ func (cmd urlsCmd )Run (fl * pflag.FlagSet ) {
205
+ envName := fl .Arg (0 )
206
+ devURLs := urlList (envName )
207
+
68
208
w := tabwriter .NewWriter (os .Stdout ,0 ,0 ,1 ,' ' ,tabwriter .TabIndent )
69
209
for _ ,devURL := range devURLs {
70
210
fmt .Fprintf (w ,"%s\t %s\t %s\n " ,devURL .URL ,devURL .Port ,devURL .Access )
71
211
}
72
212
w .Flush ()
73
213
}
214
+
215
+ func (cmd * urlsCmd )Subcommands () []cli.Command {
216
+ return []cli.Command {
217
+ & createSubCmd {},
218
+ & delSubCmd {},
219
+ }
220
+ }