-
Notifications
You must be signed in to change notification settings - Fork 10
/
command_namedport.go
128 lines (121 loc) · 3.33 KB
/
command_namedport.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
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"os/exec"
"strconv"
"strings"
"github.com/urfave/cli"
)
type namedPort struct {
Name string `json:"name"`
Port int `json:"port"`
}
const (
create = 1
delete = 2
)
func cmdCreateNamedPort(c *cli.Context) error {
return cmdChangeNamedPort(c, create)
}
func cmdDeleteNamedPort(c *cli.Context) error {
return cmdChangeNamedPort(c, delete)
}
func cmdChangeNamedPort(c *cli.Context, action int) error {
if len(c.Args()) != 2 {
return fmt.Errorf("missing command argument, expected [INSTANCE_GROUP] NAME:PORT")
}
verbose := c.GlobalBool("v")
instanceGroup := c.Args()[0]
if len(instanceGroup) == 0 {
return fmt.Errorf("missing Compute Instance Group command argument")
}
parts := strings.Split(c.Args()[1], ":")
if len(parts) == 0 {
return fmt.Errorf("invalid NAME:PORT command argument")
}
port, err := strconv.Atoi(parts[1])
if err != nil {
return fmt.Errorf("PORT must be a positive integer:%v", err)
}
name := parts[0]
// get named ports
args := []string{"compute", "instance-groups", "get-named-ports", instanceGroup, "--format", "json"}
cmd := exec.Command("gcloud", args...)
if verbose {
log.Println(strings.Join(append([]string{"gcloud"}, args...), " "))
}
data, err := runCommand(cmd)
if err != nil {
log.Println(string(data)) // stderr
return fmt.Errorf("failed to run gcloud get-named-ports: %v", err)
}
// parse named ports
var list []namedPort
if err := json.NewDecoder(bytes.NewReader(data)).Decode(&list); err != nil {
return fmt.Errorf("parsing JSON output failed:%v", err)
}
if verbose {
log.Println("current list of named ports", list)
}
if create == action {
log.Printf("ensure named port exists %s:%d\n", name, port)
// only append if not exists, update otherwise or abort
updated := false
for _, each := range list {
if each.Name == name {
if each.Port == port {
log.Printf("named-port [%s:%d] already exists\n", name, port)
return nil
}
log.Printf("change named port from [%s:%d] to [%s:%d]\n", each.Name, each.Port, each.Name, port)
each.Port = port
updated = true
break
}
}
if !updated {
list = append(list, namedPort{Name: name, Port: port})
}
}
if delete == action {
log.Printf("ensure named port no longer exists %s:%d\n", name, port)
// only delete if exists, update otherwise
deleted := false
copyWithout := []namedPort{}
for _, each := range list {
if each.Name == name {
if verbose {
log.Printf("deleted named port %s=%d\n", each.Name, each.Port)
}
deleted = true
} else {
copyWithout = append(copyWithout, each)
}
}
if !deleted {
log.Printf("named-port [%s:%d] did not exists\n", name, port)
return nil
}
list = copyWithout
}
// composed set argument
newList := new(strings.Builder)
for i, each := range list {
if i > 0 {
newList.WriteString(",")
}
fmt.Fprintf(newList, "%s:%d", each.Name, each.Port)
}
// set named ports using new list
args = []string{"compute", "instance-groups", "set-named-ports", instanceGroup, "--named-ports", newList.String()}
cmd = exec.Command("gcloud", args...)
log.Println(strings.Join(append([]string{"gcloud"}, args...), " "))
if data, err := runCommand(cmd); err != nil {
log.Println(string(data)) // stderr
return fmt.Errorf("failed to run gcloud set-named-ports: %v", err)
}
return nil
}