Merge pull request #5175 from rickard-von-essen/cloudstack-sg

cloudstack: Add support for Security Groups
This commit is contained in:
Matthew Hooker 2017-08-31 12:04:49 -07:00 committed by GitHub
commit 4884efd0d4
6 changed files with 129 additions and 4 deletions

View File

@ -71,6 +71,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
SSHAgentAuth: b.config.Comm.SSHAgentAuth,
TemporaryKeyPairName: b.config.TemporaryKeypairName,
},
&stepCreateSecurityGroup{},
&stepCreateInstance{
Ctx: b.config.ctx,
Debug: b.config.PackerDebug,

View File

@ -28,22 +28,24 @@ type Config struct {
SSLNoVerify bool `mapstructure:"ssl_no_verify"`
CIDRList []string `mapstructure:"cidr_list"`
CreateSecurityGroup bool `mapstructure:"create_security_group"`
DiskOffering string `mapstructure:"disk_offering"`
DiskSize int64 `mapstructure:"disk_size"`
Expunge bool `mapstructure:"expunge"`
Hypervisor string `mapstructure:"hypervisor"`
InstanceName string `mapstructure:"instance_name"`
Keypair string `mapstructure:"keypair"`
TemporaryKeypairName string `mapstructure:"temporary_keypair_name"`
Network string `mapstructure:"network"`
Project string `mapstructure:"project"`
PublicIPAddress string `mapstructure:"public_ip_address"`
SecurityGroups []string `mapstructure:"security_groups"`
ServiceOffering string `mapstructure:"service_offering"`
SourceTemplate string `mapstructure:"source_template"`
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"`
UserDataFile string `mapstructure:"user_data_file"`
UseLocalIPAddress bool `mapstructure:"use_local_ip_address"`
Zone string `mapstructure:"zone"`
TemplateName string `mapstructure:"template_name"`
@ -99,7 +101,7 @@ func NewConfig(raws ...interface{}) (*Config, error) {
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"}
}
@ -146,6 +148,10 @@ func NewConfig(raws ...interface{}) (*Config, error) {
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 == "" {
errs = packer.MultiErrorAppend(errs, errors.New("a service_offering must be specified"))
}

View File

@ -49,6 +49,10 @@ func (s *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction
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 config.SourceISO != "" {
p.SetDiskofferingid(config.DiskOffering)

View File

@ -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))
}
}

View File

@ -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) {
config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering)
if err != nil {

View File

@ -74,6 +74,11 @@ builder.
connect to the instance. Defaults to `[ "0.0.0.0/0" ]`. Only required
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
instance. This option is only available (and also required) when using
`source_iso`.
@ -118,6 +123,9 @@ builder.
connecting any provisioners to. If not provided, a temporary public IP
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
authenticate connections to the source instance. No temporary keypair will
be created, and the values of `ssh_password` and `ssh_private_key_file` will