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