Merge pull request #5175 from rickard-von-essen/cloudstack-sg
cloudstack: Add support for Security Groups
This commit is contained in:
commit
4884efd0d4
|
@ -71,6 +71,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
SSHAgentAuth: b.config.Comm.SSHAgentAuth,
|
SSHAgentAuth: b.config.Comm.SSHAgentAuth,
|
||||||
TemporaryKeyPairName: b.config.TemporaryKeypairName,
|
TemporaryKeyPairName: b.config.TemporaryKeypairName,
|
||||||
},
|
},
|
||||||
|
&stepCreateSecurityGroup{},
|
||||||
&stepCreateInstance{
|
&stepCreateInstance{
|
||||||
Ctx: b.config.ctx,
|
Ctx: b.config.ctx,
|
||||||
Debug: b.config.PackerDebug,
|
Debug: b.config.PackerDebug,
|
||||||
|
|
|
@ -28,22 +28,24 @@ type Config struct {
|
||||||
SSLNoVerify bool `mapstructure:"ssl_no_verify"`
|
SSLNoVerify bool `mapstructure:"ssl_no_verify"`
|
||||||
|
|
||||||
CIDRList []string `mapstructure:"cidr_list"`
|
CIDRList []string `mapstructure:"cidr_list"`
|
||||||
|
CreateSecurityGroup bool `mapstructure:"create_security_group"`
|
||||||
DiskOffering string `mapstructure:"disk_offering"`
|
DiskOffering string `mapstructure:"disk_offering"`
|
||||||
DiskSize int64 `mapstructure:"disk_size"`
|
DiskSize int64 `mapstructure:"disk_size"`
|
||||||
Expunge bool `mapstructure:"expunge"`
|
Expunge bool `mapstructure:"expunge"`
|
||||||
Hypervisor string `mapstructure:"hypervisor"`
|
Hypervisor string `mapstructure:"hypervisor"`
|
||||||
InstanceName string `mapstructure:"instance_name"`
|
InstanceName string `mapstructure:"instance_name"`
|
||||||
Keypair string `mapstructure:"keypair"`
|
Keypair string `mapstructure:"keypair"`
|
||||||
TemporaryKeypairName string `mapstructure:"temporary_keypair_name"`
|
|
||||||
Network string `mapstructure:"network"`
|
Network string `mapstructure:"network"`
|
||||||
Project string `mapstructure:"project"`
|
Project string `mapstructure:"project"`
|
||||||
PublicIPAddress string `mapstructure:"public_ip_address"`
|
PublicIPAddress string `mapstructure:"public_ip_address"`
|
||||||
|
SecurityGroups []string `mapstructure:"security_groups"`
|
||||||
ServiceOffering string `mapstructure:"service_offering"`
|
ServiceOffering string `mapstructure:"service_offering"`
|
||||||
SourceTemplate string `mapstructure:"source_template"`
|
|
||||||
SourceISO string `mapstructure:"source_iso"`
|
SourceISO string `mapstructure:"source_iso"`
|
||||||
|
SourceTemplate string `mapstructure:"source_template"`
|
||||||
|
TemporaryKeypairName string `mapstructure:"temporary_keypair_name"`
|
||||||
|
UseLocalIPAddress bool `mapstructure:"use_local_ip_address"`
|
||||||
UserData string `mapstructure:"user_data"`
|
UserData string `mapstructure:"user_data"`
|
||||||
UserDataFile string `mapstructure:"user_data_file"`
|
UserDataFile string `mapstructure:"user_data_file"`
|
||||||
UseLocalIPAddress bool `mapstructure:"use_local_ip_address"`
|
|
||||||
Zone string `mapstructure:"zone"`
|
Zone string `mapstructure:"zone"`
|
||||||
|
|
||||||
TemplateName string `mapstructure:"template_name"`
|
TemplateName string `mapstructure:"template_name"`
|
||||||
|
@ -99,7 +101,7 @@ func NewConfig(raws ...interface{}) (*Config, error) {
|
||||||
c.AsyncTimeout = 30 * time.Minute
|
c.AsyncTimeout = 30 * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.CIDRList) == 0 && !c.UseLocalIPAddress {
|
if len(c.CIDRList) == 0 {
|
||||||
c.CIDRList = []string{"0.0.0.0/0"}
|
c.CIDRList = []string{"0.0.0.0/0"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +148,10 @@ func NewConfig(raws ...interface{}) (*Config, error) {
|
||||||
errs = packer.MultiErrorAppend(errs, errors.New("a network must be specified"))
|
errs = packer.MultiErrorAppend(errs, errors.New("a network must be specified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.CreateSecurityGroup && !c.Expunge {
|
||||||
|
errs = packer.MultiErrorAppend(errs, errors.New("auto creating a temporary security group requires expunge"))
|
||||||
|
}
|
||||||
|
|
||||||
if c.ServiceOffering == "" {
|
if c.ServiceOffering == "" {
|
||||||
errs = packer.MultiErrorAppend(errs, errors.New("a service_offering must be specified"))
|
errs = packer.MultiErrorAppend(errs, errors.New("a service_offering must be specified"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,10 @@ func (s *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction
|
||||||
p.SetKeypair(keypair.(string))
|
p.SetKeypair(keypair.(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if securitygroups, ok := state.GetOk("security_groups"); ok {
|
||||||
|
p.SetSecuritygroupids(securitygroups.([]string))
|
||||||
|
}
|
||||||
|
|
||||||
// If we use an ISO, configure the disk offering.
|
// If we use an ISO, configure the disk offering.
|
||||||
if config.SourceISO != "" {
|
if config.SourceISO != "" {
|
||||||
p.SetDiskofferingid(config.DiskOffering)
|
p.SetDiskofferingid(config.DiskOffering)
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package cloudstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/common/uuid"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
|
"github.com/xanzy/go-cloudstack/cloudstack"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stepCreateSecurityGroup struct {
|
||||||
|
tempSG string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stepCreateSecurityGroup) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
client := state.Get("client").(*cloudstack.CloudStackClient)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
|
if len(config.SecurityGroups) > 0 {
|
||||||
|
state.Put("security_groups", config.SecurityGroups)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.CreateSecurityGroup {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say("Creating temporary Security Group...")
|
||||||
|
|
||||||
|
p := client.SecurityGroup.NewCreateSecurityGroupParams(
|
||||||
|
fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()),
|
||||||
|
)
|
||||||
|
p.SetDescription("Temporary SG created by Packer")
|
||||||
|
if config.Project != "" {
|
||||||
|
p.SetProjectid(config.Project)
|
||||||
|
}
|
||||||
|
|
||||||
|
sg, err := client.SecurityGroup.CreateSecurityGroup(p)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Failed to create security group: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
s.tempSG = sg.Id
|
||||||
|
state.Put("security_groups", []string{sg.Id})
|
||||||
|
|
||||||
|
// Create Ingress rule
|
||||||
|
i := client.SecurityGroup.NewAuthorizeSecurityGroupIngressParams()
|
||||||
|
i.SetCidrlist(config.CIDRList)
|
||||||
|
i.SetProtocol("TCP")
|
||||||
|
i.SetSecuritygroupid(sg.Id)
|
||||||
|
i.SetStartport(config.Comm.Port())
|
||||||
|
i.SetEndport(config.Comm.Port())
|
||||||
|
if config.Project != "" {
|
||||||
|
i.SetProjectid(config.Project)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.SecurityGroup.AuthorizeSecurityGroupIngress(i)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Failed to authorize security group ingress rule: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup any resources that may have been created during the Run phase.
|
||||||
|
func (s *stepCreateSecurityGroup) Cleanup(state multistep.StateBag) {
|
||||||
|
client := state.Get("client").(*cloudstack.CloudStackClient)
|
||||||
|
config := state.Get("config").(*Config)
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
|
if s.tempSG == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Cleanup temporary security group: %s ...", s.tempSG))
|
||||||
|
p := client.SecurityGroup.NewDeleteSecurityGroupParams()
|
||||||
|
p.SetId(s.tempSG)
|
||||||
|
if config.Project != "" {
|
||||||
|
p.SetProjectid(config.Project)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := client.SecurityGroup.DeleteSecurityGroup(p); err != nil {
|
||||||
|
ui.Error(err.Error())
|
||||||
|
ui.Error(fmt.Sprintf("Error deleting security group: %s. Please destroy it manually.\n", s.tempSG))
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,18 @@ func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then try to get the SG's UUID's.
|
||||||
|
if len(config.SecurityGroups) > 0 {
|
||||||
|
for i := range config.SecurityGroups {
|
||||||
|
if !isUUID(config.SecurityGroups[i]) {
|
||||||
|
config.SecurityGroups[i], _, err = client.SecurityGroup.GetSecurityGroupID(config.SecurityGroups[i], cloudstack.WithProject(config.Project))
|
||||||
|
if err != nil {
|
||||||
|
errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.SecurityGroups[i], err})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !isUUID(config.ServiceOffering) {
|
if !isUUID(config.ServiceOffering) {
|
||||||
config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering)
|
config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -74,6 +74,11 @@ builder.
|
||||||
connect to the instance. Defaults to `[ "0.0.0.0/0" ]`. Only required
|
connect to the instance. Defaults to `[ "0.0.0.0/0" ]`. Only required
|
||||||
when `use_local_ip_address` is `false`.
|
when `use_local_ip_address` is `false`.
|
||||||
|
|
||||||
|
- `create_security_group` (boolean) - If `true` a temporary security group
|
||||||
|
will be created which allows traffic towards the instance from the
|
||||||
|
`cidr_list`. This option will be ignored if `security_groups` is also
|
||||||
|
defined. Requires `expunge` set to `true`. Defaults to `false`.
|
||||||
|
|
||||||
- `disk_offering` (string) - The name or ID of the disk offering used for the
|
- `disk_offering` (string) - The name or ID of the disk offering used for the
|
||||||
instance. This option is only available (and also required) when using
|
instance. This option is only available (and also required) when using
|
||||||
`source_iso`.
|
`source_iso`.
|
||||||
|
@ -118,6 +123,9 @@ builder.
|
||||||
connecting any provisioners to. If not provided, a temporary public IP
|
connecting any provisioners to. If not provided, a temporary public IP
|
||||||
address will be associated and released during the Packer run.
|
address will be associated and released during the Packer run.
|
||||||
|
|
||||||
|
- `security_groups` (array of strings) - A list of security group IDs or names
|
||||||
|
to associate the instance with.
|
||||||
|
|
||||||
- `ssh_agent_auth` (boolean) - If true, the local SSH agent will be used to
|
- `ssh_agent_auth` (boolean) - If true, the local SSH agent will be used to
|
||||||
authenticate connections to the source instance. No temporary keypair will
|
authenticate connections to the source instance. No temporary keypair will
|
||||||
be created, and the values of `ssh_password` and `ssh_private_key_file` will
|
be created, and the values of `ssh_password` and `ssh_private_key_file` will
|
||||||
|
|
Loading…
Reference in New Issue