Skip to content

Commit 71878f4

Browse files
authored
Merge pull request #57 from liquidweb/secondary-ipv6
Secondary ipv6
2 parents 2f1a516 + 77b1f3d commit 71878f4

File tree

11 files changed

+139
-23
lines changed

11 files changed

+139
-23
lines changed

cmd/cloudNetworkPublicAdd.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
)
2525

2626
var cloudNetworkPublicAddCmdPoolIpsFlag []string
27+
var cloudNetworkPublicAddCmdPool6IpsFlag []string
2728

2829
var cloudNetworkPublicAddCmd = &cobra.Command{
2930
Use: "add",
@@ -37,14 +38,21 @@ operating system.
3738
If the configure-ips flag is not passed, the IP addresses will be assigned, and
3839
routing will be allowed. However the IP(s) will not be automatically configured
3940
in the guest operating system. In this scenario, it will be up to the system
40-
administrator to add the IP(s) to the network configuration.`,
41+
administrator to add the IP(s) to the network configuration.
42+
43+
IPv6 Notes:
44+
45+
Only /64s will be given out. There is a limit of one /64 per Cloud Server. If
46+
you need more than this, you can contact support.`,
4147
Run: func(cmd *cobra.Command, args []string) {
4248
params := &instance.CloudNetworkPublicAddParams{}
4349

4450
params.UniqId, _ = cmd.Flags().GetString("uniq-id")
4551
params.ConfigureIps, _ = cmd.Flags().GetBool("configure-ips")
4652
params.NewIps, _ = cmd.Flags().GetInt64("new-ips")
53+
params.NewIp6s, _ = cmd.Flags().GetInt64("new-ip6s")
4754
params.PoolIps = cloudNetworkPublicAddCmdPoolIpsFlag
55+
params.Pool6Ips = cloudNetworkPublicAddCmdPool6IpsFlag
4856

4957
status, err := lwCliInst.CloudNetworkPublicAdd(params)
5058
if err != nil {
@@ -59,10 +67,13 @@ func init() {
5967
cloudNetworkPublicCmd.AddCommand(cloudNetworkPublicAddCmd)
6068
cloudNetworkPublicAddCmd.Flags().String("uniq-id", "", "uniq-id of the Cloud Server")
6169
cloudNetworkPublicAddCmd.Flags().Bool("configure-ips", false,
62-
"wheter or not to automatically configure the new IP address(es) in the server")
63-
cloudNetworkPublicAddCmd.Flags().Int64("new-ips", 0, "amount of new ips to (randomly) grab")
70+
"whether or not to automatically configure the new IP address(es) in the server")
71+
cloudNetworkPublicAddCmd.Flags().Int64("new-ips", 0, "amount of new IPv4 ips to (randomly) grab")
72+
cloudNetworkPublicAddCmd.Flags().Int64("new-ip6s", 0, "amount of new IPv6 /64's to (randomly) grab")
6473
cloudNetworkPublicAddCmd.Flags().StringSliceVar(&cloudNetworkPublicAddCmdPoolIpsFlag, "pool-ips", []string{},
65-
"ips from your IP Pool separated by ',' to assign to the Cloud Server")
74+
"IPv4 ips from your IP Pool separated by ',' to assign to the Cloud Server")
75+
cloudNetworkPublicAddCmd.Flags().StringSliceVar(&cloudNetworkPublicAddCmdPool6IpsFlag, "pool6-ips", []string{},
76+
"IPv6 assignments from your IP Pool separated by ',' to assign to the Cloud Server")
6677

6778
if err := cloudNetworkPublicAddCmd.MarkFlagRequired("uniq-id"); err != nil {
6879
lwCliInst.Die(err)

cmd/cloudServerClone.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
)
2828

2929
var cloudServerCloneCmdPoolIpsFlag []string
30+
var cloudServerCloneCmdPool6IpsFlag []string
3031

3132
var cloudServerCloneCmd = &cobra.Command{
3233
Use: "clone",
@@ -52,6 +53,7 @@ Server is not on a Private Parent.`,
5253
passwordFlag, _ := cmd.Flags().GetString("password")
5354
zoneFlag, _ := cmd.Flags().GetInt64("zone")
5455
newIpsFlag, _ := cmd.Flags().GetInt64("new-ips")
56+
newIp6sFlag, _ := cmd.Flags().GetInt64("new-ip6s")
5557
hostnameFlag, _ := cmd.Flags().GetString("hostname")
5658
privateParentFlag, _ := cmd.Flags().GetString("private-parent")
5759
diskspaceFlag, _ := cmd.Flags().GetInt64("diskspace")
@@ -86,9 +88,10 @@ Server is not on a Private Parent.`,
8688

8789
// buildout api bleed/server/clone parameters
8890
cloneArgs := map[string]interface{}{
89-
"uniq_id": uniqIdFlag,
90-
"domain": hostnameFlag,
91-
"new_ips": newIpsFlag,
91+
"uniq_id": uniqIdFlag,
92+
"domain": hostnameFlag,
93+
"new_ips": newIpsFlag,
94+
"new_ip6s": newIp6sFlag,
9295
}
9396
if passwordFlag != "" {
9497
cloneArgs["password"] = passwordFlag
@@ -122,6 +125,12 @@ Server is not on a Private Parent.`,
122125
validateFields[ip] = "IP"
123126
}
124127
}
128+
if len(cloudServerCloneCmdPool6IpsFlag) > 0 {
129+
cloneArgs["pool6_ips"] = cloudServerCloneCmdPool6IpsFlag
130+
for _, ip := range cloudServerCloneCmdPool6IpsFlag {
131+
validateFields[ip] = "CIDR"
132+
}
133+
}
125134

126135
if err := validate.Validate(validateFields); err != nil {
127136
lwCliInst.Die(err)
@@ -146,11 +155,14 @@ func init() {
146155
cloudServerCloneCmd.Flags().String("uniq-id", "", "uniq-id of Cloud Server to clone")
147156
cloudServerCloneCmd.Flags().String("password", "", "root or administrator password for new Cloud Server")
148157
cloudServerCloneCmd.Flags().Int64("zone", -1, "zone for new Cloud Server")
149-
cloudServerCloneCmd.Flags().Int64("new-ips", 1, "amount of IP addresses for new Cloud Server")
158+
cloudServerCloneCmd.Flags().Int64("new-ips", 1, "amount of IPv4 addresses for the new Cloud Server")
159+
cloudServerCloneCmd.Flags().Int64("new-ip6s", 0, "amount of new IPv6 /64's for the new Cloud Server")
150160
cloudServerCloneCmd.Flags().String("hostname", fmt.Sprintf("%s.%s.io", utils.RandomString(4),
151161
utils.RandomString(10)), "hostname for new Cloud Server")
152162
cloudServerCloneCmd.Flags().StringSliceVar(&cloudServerCloneCmdPoolIpsFlag, "pool-ips", []string{},
153-
"ips from your IP Pool separated by ',' to assign to the new Cloud Server")
163+
"IPv4 ips from your IP Pool separated by ',' to assign to the new Cloud Server")
164+
cloudServerCloneCmd.Flags().StringSliceVar(&cloudServerCloneCmdPool6IpsFlag, "pool6-ips", []string{},
165+
"IPv6 ips from your IP Pool separated by ',' to assign to the new Cloud Server")
154166

155167
// Private Parent
156168
cloudServerCloneCmd.Flags().String("private-parent", "",

cmd/cloudServerCreate.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
)
2929

3030
var cloudServerCreateCmdPoolIpsFlag []string
31+
var cloudServerCreateCmdPool6IpsFlag []string
3132

3233
var cloudServerCreateCmd = &cobra.Command{
3334
Use: "create",
@@ -68,6 +69,7 @@ cloud:
6869
zone: 40460
6970
hostname: "db1.dev.addictmud.org"
7071
ips: 1
72+
ip6s: 1
7173
public-ssh-key: ""
7274
config-id: 88
7375
backup-days: 5
@@ -77,6 +79,8 @@ cloud:
7779
pool-ips:
7880
- "10.111.12.13"
7981
- "10.12.13.14"
82+
pool6-ips:
83+
- "2607:fad0:3714:350c::/64"
8084
private-parent: "my pp"
8185
memory: 0
8286
diskspace: 0
@@ -93,6 +97,7 @@ lw plan --file /tmp/cloud.server.create.yaml
9397
params.Type, _ = cmd.Flags().GetString("type")
9498
params.Hostname, _ = cmd.Flags().GetString("hostname")
9599
params.Ips, _ = cmd.Flags().GetInt("ips")
100+
params.Ip6s, _ = cmd.Flags().GetInt("ip6s")
96101
pubSshKey, _ := cmd.Flags().GetString("public-ssh-key")
97102
params.ConfigId, _ = cmd.Flags().GetInt("config-id")
98103
params.BackupDays, _ = cmd.Flags().GetInt("backup-days")
@@ -108,6 +113,8 @@ lw plan --file /tmp/cloud.server.create.yaml
108113
params.Vcpu, _ = cmd.Flags().GetInt("vcpu")
109114
params.BackupId, _ = cmd.Flags().GetInt("backup-id")
110115
params.ImageId, _ = cmd.Flags().GetInt("image-id")
116+
params.PoolIps = cloudServerCreateCmdPoolIpsFlag
117+
params.Pool6Ips = cloudServerCreateCmdPool6IpsFlag
111118

112119
sshPkeyContents, err := ioutil.ReadFile(filepath.Clean(pubSshKey))
113120
if err == nil {
@@ -137,7 +144,8 @@ func init() {
137144
cloudServerCreateCmd.Flags().String("template", cast.ToString(defaultFlag("cloud_server_create_template")), "template to use (see 'cloud server options --templates')")
138145
cloudServerCreateCmd.Flags().String("type", "SS.VPS", "some examples of types; SS.VPS, SS.VPS.WIN, SS.VM, SS.VM.WIN")
139146
cloudServerCreateCmd.Flags().String("hostname", "", "hostname to set")
140-
cloudServerCreateCmd.Flags().Int("ips", 1, "amount of IP addresses")
147+
cloudServerCreateCmd.Flags().Int("ips", 1, "amount of IPv4 addresses")
148+
cloudServerCreateCmd.Flags().Int("ip6s", 0, "amount of IPv6 /64s")
141149
cloudServerCreateCmd.Flags().String("public-ssh-key", sshPubKeyFile,
142150
"path to file containing the public ssh key you wish to be on the new Cloud Server")
143151
cloudServerCreateCmd.Flags().Int("config-id", cast.ToInt(defaultFlag("cloud_server_create_config-id", -1)), "config-id to use")
@@ -151,7 +159,10 @@ func init() {
151159
cloudServerCreateCmd.Flags().Int("image-id", -1, "id of cloud image to create from (see 'cloud image list')")
152160

153161
cloudServerCreateCmd.Flags().StringSliceVar(&cloudServerCreateCmdPoolIpsFlag, "pool-ips", []string{},
154-
"ips from your IP Pool separated by ',' to assign to the new Cloud Server")
162+
"IPv4 ips from your IP Pool separated by ',' to assign to the new Cloud Server")
163+
164+
cloudServerCreateCmd.Flags().StringSliceVar(&cloudServerCreateCmdPool6IpsFlag, "pool6-ips", []string{},
165+
"IPv6 assignments from your IP Pool separated by ',' to assign to the new Cloud Server")
155166

156167
// private parent specific
157168
cloudServerCreateCmd.Flags().String("private-parent", "",

cmd/networkIpPoolUpdate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ your account.`,
5555
if len(networkIpPoolUpdateCmdAddIpsFlag) > 0 {
5656
apiArgs["add_ips"] = networkIpPoolUpdateCmdAddIpsFlag
5757
for _, ip := range networkIpPoolUpdateCmdAddIpsFlag {
58-
validateFields[ip] = "IP"
58+
validateFields[ip] = "IpOrCidr"
5959
}
6060
}
6161
if len(networkIpPoolUpdateCmdRemoveIpsFlag) > 0 {
6262
apiArgs["remove_ips"] = networkIpPoolUpdateCmdRemoveIpsFlag
6363
for _, ip := range networkIpPoolUpdateCmdRemoveIpsFlag {
64-
validateFields[ip] = "IP"
64+
validateFields[ip] = "IpOrCidr"
6565
}
6666
}
6767
if newIpsFlag != -1 {

instance/cloudNetworkPublicAdd.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ type CloudNetworkPublicAddParams struct {
2727
UniqId string `yaml:"uniq-id"`
2828
ConfigureIps bool `yaml:"configure-ips"`
2929
NewIps int64 `yaml:"new-ips"`
30+
NewIp6s int64 `yaml:"new-ip6s"`
3031
PoolIps []string `yaml:"pool-ips"`
32+
Pool6Ips []string `yaml:"pool6-ips"`
3133
}
3234

3335
func (self *CloudNetworkPublicAddParams) UnmarshalYAML(unmarshal func(interface{}) error) error {
@@ -50,8 +52,8 @@ func (self *Client) CloudNetworkPublicAdd(params *CloudNetworkPublicAddParams) (
5052
return
5153
}
5254

53-
if params.NewIps == 0 && len(params.PoolIps) == 0 {
54-
err = fmt.Errorf("at least one of --new-ips --pool-ips must be given")
55+
if params.NewIps == 0 && len(params.PoolIps) == 0 && params.NewIp6s == 0 && len(params.Pool6Ips) == 0 {
56+
err = fmt.Errorf("at least one of --new-ips --pool-ips --new-ip6s --pool6-ips must be given")
5557
return
5658
}
5759

@@ -77,6 +79,24 @@ func (self *Client) CloudNetworkPublicAdd(params *CloudNetworkPublicAddParams) (
7779
}
7880
}
7981

82+
if params.NewIp6s != 0 {
83+
apiArgs["ip6_count"] = params.NewIp6s
84+
validateFields := map[interface{}]interface{}{params.NewIps: "PositiveInt64"}
85+
if err = validate.Validate(validateFields); err != nil {
86+
return
87+
}
88+
}
89+
if len(params.Pool6Ips) != 0 {
90+
apiArgs["pool6_ips"] = params.Pool6Ips
91+
validateFields := map[interface{}]interface{}{}
92+
for _, ip := range params.Pool6Ips {
93+
validateFields[ip] = "CIDR"
94+
}
95+
if err = validate.Validate(validateFields); err != nil {
96+
return
97+
}
98+
}
99+
80100
var details apiTypes.NetworkIpAdd
81101
if err = self.CallLwApiInto("bleed/network/ip/add", apiArgs, &details); err != nil {
82102
return

instance/cloudNetworkPublicRemove.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (self *Client) CloudNetworkPublicRemove(params *CloudNetworkPublicRemovePar
6262
var b bytes.Buffer
6363
for _, ip := range params.Ips {
6464
validateFields := map[interface{}]interface{}{
65-
ip: "IP",
65+
ip: "IpOrCidr",
6666
}
6767
if err := validate.Validate(validateFields); err != nil {
6868
fmt.Printf("%s ... skipping\n", err)

instance/cloudServerCreate.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ type CloudServerCreateParams struct {
3131
Type string `yaml:"type"`
3232
Hostname string `yaml:"hostname"`
3333
Ips int `yaml:"ips"`
34+
Ip6s int `yaml:"ip6s"`
3435
PoolIps []string `yaml:"pool-ips"`
36+
Pool6Ips []string `yaml:"pool6-ips"`
3537
PublicSshKey string `yaml:"public-ssh-key"`
3638
ConfigId int `yaml:"config-id"`
3739
BackupDays int `yaml:"backup-days"` // daily backup plan; how many days to keep a backup
@@ -166,11 +168,12 @@ func (ci *Client) CloudServerCreate(params *CloudServerCreateParams) (string, er
166168

167169
// buildout args for bleed/server/create
168170
createArgs := map[string]interface{}{
169-
"domain": params.Hostname,
170-
"pool_ips": params.PoolIps,
171-
"new_ips": params.Ips,
172-
"zone": params.Zone,
173-
"password": params.Password,
171+
"domain": params.Hostname,
172+
"pool_ips": params.PoolIps,
173+
"pool6_ips": params.Pool6Ips,
174+
"new_ips": params.Ips,
175+
"zone": params.Zone,
176+
"password": params.Password,
174177
"features": map[string]interface{}{
175178
"Bandwidth": params.Bandwidth,
176179
"ConfigId": params.ConfigId,
@@ -182,6 +185,10 @@ func (ci *Client) CloudServerCreate(params *CloudServerCreateParams) (string, er
182185
},
183186
}
184187

188+
if params.Ip6s > 0 {
189+
createArgs["new_ip6s"] = params.Ip6s
190+
}
191+
185192
var isWindows bool
186193
if params.Template != "" {
187194
createArgs["features"].(map[string]interface{})["Template"] = params.Template

types/api/network.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,13 @@ func (x NetworkAssignmentListEntry) String() string {
9696
var slice []string
9797

9898
slice = append(slice, fmt.Sprintf("\tIP: %s\n", x.Ip))
99+
slice = append(slice, fmt.Sprintf("\t\tNetwork: %s\n", x.Network))
99100
slice = append(slice, fmt.Sprintf("\t\tId: %d\n", x.Id))
100101
slice = append(slice, fmt.Sprintf("\t\tGateway: %s\n", x.Gateway))
101-
slice = append(slice, fmt.Sprintf("\t\tBroadcast: %s\n", x.Broadcast))
102+
if x.Broadcast != "" {
103+
slice = append(slice, fmt.Sprintf("\t\tBroadcast: %s\n", x.Broadcast))
104+
}
102105
slice = append(slice, fmt.Sprintf("\t\tNetmask: %s\n", x.Netmask))
103-
slice = append(slice, fmt.Sprintf("\t\tNetwork: %s\n", x.Netmask))
104106

105107
return strings.Join(slice[:], "")
106108
}

utils/utils.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ func IpIsValid(ip string) bool {
3333
return true
3434
}
3535

36+
func IpRangeIsValid(cidr string) bool {
37+
if _, _, err := net.ParseCIDR(cidr); err != nil {
38+
return false
39+
}
40+
41+
return true
42+
}
43+
3644
func RandomString(length int) string {
3745
charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + "0123456789"
3846
var seededRand *rand.Rand = rand.New(

validate/types.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ var ValidationFailure = errors.New("validation failed")
3333
type InputTypes struct {
3434
UniqId InputTypeUniqId
3535
IP InputTypeIP
36+
CIDR InputTypeCIDR
37+
IpOrCidr InputTypeIpOrCidr
3638
PositiveInt64 InputTypePositiveInt64
3739
PositiveInt InputTypePositiveInt
3840
NonEmptyString InputTypeNonEmptyString
@@ -90,6 +92,37 @@ func (x InputTypeIP) Validate() error {
9092
return nil
9193
}
9294

95+
// CIDR
96+
97+
type InputTypeCIDR struct {
98+
CIDR string
99+
}
100+
101+
func (x InputTypeCIDR) Validate() error {
102+
if valid := utils.IpRangeIsValid(x.CIDR); !valid {
103+
return fmt.Errorf("cidr [%s] is not valid", x.CIDR)
104+
}
105+
106+
return nil
107+
}
108+
109+
// IpOrCidr
110+
111+
type InputTypeIpOrCidr struct {
112+
IpOrCidr string
113+
}
114+
115+
func (x InputTypeIpOrCidr) Validate() error {
116+
ipRangeIsValid := utils.IpRangeIsValid(x.IpOrCidr)
117+
ipIsValid := utils.IpIsValid(x.IpOrCidr)
118+
119+
if !ipIsValid && !ipRangeIsValid {
120+
return fmt.Errorf("ip [%s] is not a valid IP or CIDR", x.IpOrCidr)
121+
}
122+
123+
return nil
124+
}
125+
93126
// PositiveInt64
94127

95128
type InputTypePositiveInt64 struct {

0 commit comments

Comments
 (0)