@@ -3,8 +3,10 @@ package main
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
+ "math"
6
7
"net/http"
7
8
"os"
9
+ "regexp"
8
10
"strconv"
9
11
"strings"
10
12
"text/tabwriter"
@@ -21,7 +23,7 @@ type urlsCmd struct{}
21
23
type DevURL struct {
22
24
ID string `json:"id"`
23
25
URL string `json:"url"`
24
- Port string `json:"port"`
26
+ Port int `json:"port"`
25
27
Access string `json:"access"`
26
28
}
27
29
@@ -33,55 +35,66 @@ var urlAccessLevel = map[string]string{
33
35
"PUBLIC" : "Anyone on the internet can access this link" ,
34
36
}
35
37
36
- func portIsValid (port string ) bool {
38
+ func validatePort (port string ) ( int , error ) {
37
39
p , err := strconv .ParseUint (port , 10 , 16 )
38
- if p < 1 {
40
+ if p < 1 || p > math . MaxUint16 {
39
41
// port 0 means 'any free port', which we don't support
40
42
err = strconv .ErrRange
41
43
}
42
44
if err != nil {
43
- fmt .Println ("Invalid port" )
45
+ flog .Error ("Invalid port" )
46
+ return 0 , err
44
47
}
45
- return err == nil
48
+ return int ( p ), nil
46
49
}
47
50
48
51
func accessLevelIsValid (level string ) bool {
49
52
_ , ok := urlAccessLevel [level ]
50
53
if ! ok {
51
- fmt . Println ("Invalid access level" )
54
+ flog . Error ("Invalid access level" )
52
55
}
53
56
return ok
54
57
}
55
58
56
59
type createSubCmd struct {
57
- access string
60
+ access string
61
+ urlname string
58
62
}
59
63
60
64
func (sub * createSubCmd ) RegisterFlags (fl * pflag.FlagSet ) {
61
65
fl .StringVarP (& sub .access , "access" , "a" , "private" , "[private | org | authed | public] set devurl access" )
66
+ fl .StringVarP (& sub .urlname , "name" , "n" , "" , "devurl name" )
62
67
}
63
68
64
69
func (sub createSubCmd ) Spec () cli.CommandSpec {
65
70
return cli.CommandSpec {
66
- Name : "create" ,
67
- Usage : "<env name> <port> [--access <level>]" ,
68
- Desc : "create/update a devurl for external access" ,
71
+ Name : "create" ,
72
+ Usage : "<env name> <port> [--access <level>] [--name <name>]" ,
73
+ Aliases : []string {"edit" },
74
+ Desc : "create or update a devurl for external access" ,
69
75
}
70
76
}
71
77
78
+ // devURLNameValidRx is the regex used to validate devurl names specified
79
+ // via the --name subcommand. Named devurls must begin with a letter, and
80
+ // consist solely of letters and digits, with a max length of 64 chars.
81
+ var devURLNameValidRx = regexp .MustCompile ("^[a-zA-Z][a-zA-Z0-9]{0,63}$" )
82
+
72
83
// Run creates or updates a devURL, specified by env ID and port
73
84
// (fl.Arg(0) and fl.Arg(1)), with access level (fl.Arg(2)) on
74
85
// the cemanager.
75
86
func (sub createSubCmd ) Run (fl * pflag.FlagSet ) {
76
87
envName := fl .Arg (0 )
77
88
port := fl .Arg (1 )
78
- access := fl .Arg (2 )
89
+ name := fl .Arg (2 )
90
+ access := fl .Arg (3 )
79
91
80
92
if envName == "" {
81
93
exitUsage (fl )
82
94
}
83
95
84
- if ! portIsValid (port ) {
96
+ portNum , err := validatePort (port )
97
+ if err != nil {
85
98
exitUsage (fl )
86
99
}
87
100
@@ -90,20 +103,28 @@ func (sub createSubCmd) Run(fl *pflag.FlagSet) {
90
103
exitUsage (fl )
91
104
}
92
105
106
+ name = sub .urlname
107
+ if name != "" && ! devURLNameValidRx .MatchString (name ) {
108
+ flog .Error ("update devurl: name must be < 64 chars in length, begin with a letter and only contain letters or digits." )
109
+ return
110
+ }
93
111
entClient := requireAuth ()
94
112
95
113
env := findEnv (entClient , envName )
96
114
97
- _ , found := devURLID (port , urlList (envName ))
115
+ found , urlID := devURLID (portNum , urlList (envName ))
98
116
if found {
99
- fmt .Printf ("Updating devurl for port %v\n " , port )
117
+ flog .Info ("Updating devurl for port %v" , port )
118
+ err := entClient .UpdateDevURL (env .ID , urlID , portNum , name , access )
119
+ if err != nil {
120
+ flog .Error ("update devurl: %s" , err .Error ())
121
+ }
100
122
} 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 ())
123
+ flog .Info ("Adding devurl for port %v" , port )
124
+ err := entClient .InsertDevURL (env .ID , portNum , name , access )
125
+ if err != nil {
126
+ flog .Error ("insert devurl: %s" , err .Error ())
127
+ }
107
128
}
108
129
}
109
130
@@ -117,15 +138,16 @@ func (sub delSubCmd) Spec() cli.CommandSpec {
117
138
}
118
139
}
119
140
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 ) {
141
+ // devURLID returns the ID of a devURL, given the env name and port
142
+ // from a list of DevURL records.
143
+ // (false, "") is returned if no match is found.
144
+ func devURLID (port int , urls []DevURL ) (bool , string ) {
123
145
for _ , url := range urls {
124
146
if url .Port == port {
125
- return url .ID , true
147
+ return true , url .ID
126
148
}
127
149
}
128
- return "" , false
150
+ return false , ""
129
151
}
130
152
131
153
// Run deletes a devURL, specified by env ID and port, from the cemanager.
@@ -137,22 +159,22 @@ func (sub delSubCmd) Run(fl *pflag.FlagSet) {
137
159
exitUsage (fl )
138
160
}
139
161
140
- if ! portIsValid (port ) {
162
+ portNum , err := validatePort (port )
163
+ if err != nil {
141
164
exitUsage (fl )
142
165
}
143
166
144
167
entClient := requireAuth ()
145
-
146
168
env := findEnv (entClient , envName )
147
169
148
- urlID , found := devURLID (port , urlList (envName ))
170
+ found , urlID := devURLID (portNum , urlList (envName ))
149
171
if found {
150
- fmt . Printf ("Deleting devurl for port %v\n " , port )
172
+ flog . Info ("Deleting devurl for port %v" , port )
151
173
} else {
152
174
flog .Fatal ("No devurl found for port %v" , port )
153
175
}
154
176
155
- err : = entClient .DelDevURL (env .ID , urlID )
177
+ err = entClient .DelDevURL (env .ID , urlID )
156
178
if err != nil {
157
179
flog .Error ("delete devurl: %s" , err .Error ())
158
180
}
@@ -192,10 +214,6 @@ func urlList(envName string) []DevURL {
192
214
flog .Fatal ("%v" , err )
193
215
}
194
216
195
- if len (devURLs ) == 0 {
196
- fmt .Printf ("no dev urls were found for environment: %s\n " , envName )
197
- }
198
-
199
217
return devURLs
200
218
}
201
219
@@ -207,7 +225,7 @@ func (cmd urlsCmd) Run(fl *pflag.FlagSet) {
207
225
208
226
w := tabwriter .NewWriter (os .Stdout , 0 , 0 , 1 , ' ' , tabwriter .TabIndent )
209
227
for _ , devURL := range devURLs {
210
- fmt .Fprintf (w , "%s\t %s \t %s\n " , devURL .URL , devURL .Port , devURL .Access )
228
+ fmt .Fprintf (w , "%s\t %d \t %s\n " , devURL .URL , devURL .Port , devURL .Access )
211
229
}
212
230
w .Flush ()
213
231
}
0 commit comments