github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/cloudstack/step_configure_networking.go (about) 1 package cloudstack 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/packer/helper/multistep" 11 "github.com/hashicorp/packer/packer" 12 "github.com/xanzy/go-cloudstack/cloudstack" 13 ) 14 15 type stepSetupNetworking struct { 16 privatePort int 17 publicPort int 18 } 19 20 func (s *stepSetupNetworking) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 21 client := state.Get("client").(*cloudstack.CloudStackClient) 22 config := state.Get("config").(*Config) 23 ui := state.Get("ui").(packer.Ui) 24 25 ui.Say("Setup networking...") 26 27 if config.UseLocalIPAddress { 28 ui.Message("Using the local IP address...") 29 state.Put("commPort", config.Comm.Port()) 30 ui.Message("Networking has been setup!") 31 return multistep.ActionContinue 32 } 33 34 // Generate a random public port used to configure our port forward. 35 rand.Seed(time.Now().UnixNano()) 36 s.publicPort = 50000 + rand.Intn(10000) 37 state.Put("commPort", s.publicPort) 38 39 // Set the currently configured port to be the private port. 40 s.privatePort = config.Comm.Port() 41 42 // Retrieve the instance ID from the previously saved state. 43 instanceID, ok := state.Get("instance_id").(string) 44 if !ok || instanceID == "" { 45 err := fmt.Errorf("Could not retrieve instance_id from state!") 46 state.Put("error", err) 47 ui.Error(err.Error()) 48 return multistep.ActionHalt 49 } 50 51 network, _, err := client.Network.GetNetworkByID( 52 config.Network, 53 cloudstack.WithProject(config.Project), 54 ) 55 if err != nil { 56 err := fmt.Errorf("Failed to retrieve the network object: %s", err) 57 state.Put("error", err) 58 ui.Error(err.Error()) 59 return multistep.ActionHalt 60 } 61 62 if config.PublicIPAddress == "" { 63 ui.Message("Associating public IP address...") 64 p := client.Address.NewAssociateIpAddressParams() 65 66 if config.Project != "" { 67 p.SetProjectid(config.Project) 68 } 69 70 if network.Vpcid != "" { 71 p.SetVpcid(network.Vpcid) 72 } else { 73 p.SetNetworkid(network.Id) 74 } 75 76 p.SetZoneid(config.Zone) 77 78 // Associate a new public IP address. 79 ipAddr, err := client.Address.AssociateIpAddress(p) 80 if err != nil { 81 err := fmt.Errorf("Failed to associate public IP address: %s", err) 82 state.Put("error", err) 83 ui.Error(err.Error()) 84 return multistep.ActionHalt 85 } 86 87 // Set the IP address and it's ID. 88 config.PublicIPAddress = ipAddr.Id 89 state.Put("ipaddress", ipAddr.Ipaddress) 90 91 // Store the IP address ID. 92 state.Put("ip_address_id", ipAddr.Id) 93 } 94 95 ui.Message("Creating port forward...") 96 p := client.Firewall.NewCreatePortForwardingRuleParams( 97 config.PublicIPAddress, 98 s.privatePort, 99 "TCP", 100 s.publicPort, 101 instanceID, 102 ) 103 104 // Configure the port forward. 105 p.SetNetworkid(network.Id) 106 p.SetOpenfirewall(false) 107 108 // Create the port forward. 109 forward, err := client.Firewall.CreatePortForwardingRule(p) 110 if err != nil { 111 err := fmt.Errorf("Failed to create port forward: %s", err) 112 state.Put("error", err) 113 ui.Error(err.Error()) 114 return multistep.ActionHalt 115 } 116 117 // Store the port forward ID. 118 state.Put("port_forward_id", forward.Id) 119 120 if config.PreventFirewallChanges { 121 ui.Message("Networking has been setup (without firewall changes)!") 122 return multistep.ActionContinue 123 } 124 125 if network.Vpcid != "" { 126 ui.Message("Creating network ACL rule...") 127 128 if network.Aclid == "" { 129 err := fmt.Errorf("Failed to configure the firewall: no ACL connected to the VPC network") 130 state.Put("error", err) 131 ui.Error(err.Error()) 132 return multistep.ActionHalt 133 } 134 135 // Create a new parameter struct. 136 p := client.NetworkACL.NewCreateNetworkACLParams("TCP") 137 138 // Configure the network ACL rule. 139 p.SetAclid(network.Aclid) 140 p.SetAction("allow") 141 p.SetCidrlist(config.CIDRList) 142 p.SetStartport(s.privatePort) 143 p.SetEndport(s.privatePort) 144 p.SetTraffictype("ingress") 145 146 // Create the network ACL rule. 147 aclRule, err := client.NetworkACL.CreateNetworkACL(p) 148 if err != nil { 149 err := fmt.Errorf("Failed to create network ACL rule: %s", err) 150 state.Put("error", err) 151 ui.Error(err.Error()) 152 return multistep.ActionHalt 153 } 154 155 // Store the network ACL rule ID. 156 state.Put("network_acl_rule_id", aclRule.Id) 157 } else { 158 ui.Message("Creating firewall rule...") 159 160 // Create a new parameter struct. 161 p := client.Firewall.NewCreateFirewallRuleParams(config.PublicIPAddress, "TCP") 162 163 // Configure the firewall rule. 164 p.SetCidrlist(config.CIDRList) 165 p.SetStartport(s.publicPort) 166 p.SetEndport(s.publicPort) 167 168 fwRule, err := client.Firewall.CreateFirewallRule(p) 169 if err != nil { 170 err := fmt.Errorf("Failed to create firewall rule: %s", err) 171 state.Put("error", err) 172 ui.Error(err.Error()) 173 return multistep.ActionHalt 174 } 175 176 // Store the firewall rule ID. 177 state.Put("firewall_rule_id", fwRule.Id) 178 } 179 180 ui.Message("Networking has been setup!") 181 return multistep.ActionContinue 182 } 183 184 // Cleanup any resources that may have been created during the Run phase. 185 func (s *stepSetupNetworking) Cleanup(state multistep.StateBag) { 186 client := state.Get("client").(*cloudstack.CloudStackClient) 187 ui := state.Get("ui").(packer.Ui) 188 189 ui.Say("Cleanup networking...") 190 191 if fwRuleID, ok := state.Get("firewall_rule_id").(string); ok && fwRuleID != "" { 192 // Create a new parameter struct. 193 p := client.Firewall.NewDeleteFirewallRuleParams(fwRuleID) 194 195 ui.Message("Deleting firewall rule...") 196 if _, err := client.Firewall.DeleteFirewallRule(p); err != nil { 197 // This is a very poor way to be told the ID does no longer exist :( 198 if !strings.Contains(err.Error(), fmt.Sprintf( 199 "Invalid parameter id value=%s due to incorrect long value format, "+ 200 "or entity does not exist", fwRuleID)) { 201 ui.Error(fmt.Sprintf("Error deleting firewall rule: %s", err)) 202 } 203 } 204 } 205 206 if aclRuleID, ok := state.Get("network_acl_rule_id").(string); ok && aclRuleID != "" { 207 // Create a new parameter struct. 208 p := client.NetworkACL.NewDeleteNetworkACLParams(aclRuleID) 209 210 ui.Message("Deleting network ACL rule...") 211 if _, err := client.NetworkACL.DeleteNetworkACL(p); err != nil { 212 // This is a very poor way to be told the ID does no longer exist :( 213 if !strings.Contains(err.Error(), fmt.Sprintf( 214 "Invalid parameter id value=%s due to incorrect long value format, "+ 215 "or entity does not exist", aclRuleID)) { 216 ui.Error(fmt.Sprintf("Error deleting network ACL rule: %s", err)) 217 } 218 } 219 } 220 221 if forwardID, ok := state.Get("port_forward_id").(string); ok && forwardID != "" { 222 // Create a new parameter struct. 223 p := client.Firewall.NewDeletePortForwardingRuleParams(forwardID) 224 225 ui.Message("Deleting port forward...") 226 if _, err := client.Firewall.DeletePortForwardingRule(p); err != nil { 227 // This is a very poor way to be told the ID does no longer exist :( 228 if !strings.Contains(err.Error(), fmt.Sprintf( 229 "Invalid parameter id value=%s due to incorrect long value format, "+ 230 "or entity does not exist", forwardID)) { 231 ui.Error(fmt.Sprintf("Error deleting port forward: %s", err)) 232 } 233 } 234 } 235 236 if ipAddrID, ok := state.Get("ip_address_id").(string); ok && ipAddrID != "" { 237 // Create a new parameter struct. 238 p := client.Address.NewDisassociateIpAddressParams(ipAddrID) 239 240 ui.Message("Releasing public IP address...") 241 if _, err := client.Address.DisassociateIpAddress(p); err != nil { 242 // This is a very poor way to be told the ID does no longer exist :( 243 if !strings.Contains(err.Error(), fmt.Sprintf( 244 "Invalid parameter id value=%s due to incorrect long value format, "+ 245 "or entity does not exist", ipAddrID)) { 246 ui.Error(fmt.Sprintf("Error releasing public IP address: %s", err)) 247 } 248 } 249 } 250 251 ui.Message("Networking has been cleaned!") 252 return 253 }