feature: bsusurrogate, add security group step
This commit is contained in:
parent
cef9a4b9fd
commit
5ef3e81234
|
@ -158,6 +158,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
Comm: &b.config.RunConfig.Comm,
|
Comm: &b.config.RunConfig.Comm,
|
||||||
DebugKeyPath: fmt.Sprintf("oapi_%s.pem", b.config.PackerBuildName),
|
DebugKeyPath: fmt.Sprintf("oapi_%s.pem", b.config.PackerBuildName),
|
||||||
},
|
},
|
||||||
|
&osccommon.StepSecurityGroup{
|
||||||
|
SecurityGroupFilter: b.config.SecurityGroupFilter,
|
||||||
|
SecurityGroupIds: b.config.SecurityGroupIds,
|
||||||
|
CommConfig: &b.config.RunConfig.Comm,
|
||||||
|
TemporarySGSourceCidr: b.config.TemporarySGSourceCidr,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
|
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
|
||||||
|
|
|
@ -12,19 +12,19 @@ func buildNetFilters(input map[string]string) oapi.FiltersNet {
|
||||||
for k, v := range input {
|
for k, v := range input {
|
||||||
filterValue := []string{v}
|
filterValue := []string{v}
|
||||||
switch name := k; name {
|
switch name := k; name {
|
||||||
case "ip_range":
|
case "ip-range":
|
||||||
filters.IpRanges = filterValue
|
filters.IpRanges = filterValue
|
||||||
case "dhcp_options_set_id":
|
case "dhcp-options-set-id":
|
||||||
filters.DhcpOptionsSetIds = filterValue
|
filters.DhcpOptionsSetIds = filterValue
|
||||||
case "is_default":
|
case "is-default":
|
||||||
if isDefault, err := strconv.ParseBool(v); err == nil {
|
if isDefault, err := strconv.ParseBool(v); err == nil {
|
||||||
filters.IsDefault = isDefault
|
filters.IsDefault = isDefault
|
||||||
}
|
}
|
||||||
case "state":
|
case "state":
|
||||||
filters.States = filterValue
|
filters.States = filterValue
|
||||||
case "tag_key":
|
case "tag-key":
|
||||||
filters.TagKeys = filterValue
|
filters.TagKeys = filterValue
|
||||||
case "tag_value":
|
case "tag-value":
|
||||||
filters.TagValues = filterValue
|
filters.TagValues = filterValue
|
||||||
default:
|
default:
|
||||||
log.Printf("[Debug] Unknown Filter Name: %s.", name)
|
log.Printf("[Debug] Unknown Filter Name: %s.", name)
|
||||||
|
@ -38,19 +38,19 @@ func buildSubnetFilters(input map[string]string) oapi.FiltersSubnet {
|
||||||
for k, v := range input {
|
for k, v := range input {
|
||||||
filterValue := []string{v}
|
filterValue := []string{v}
|
||||||
switch name := k; name {
|
switch name := k; name {
|
||||||
case "available_ips_counts":
|
case "available-ips-counts":
|
||||||
if ipCount, err := strconv.Atoi(v); err == nil {
|
if ipCount, err := strconv.Atoi(v); err == nil {
|
||||||
filters.AvailableIpsCounts = []int64{int64(ipCount)}
|
filters.AvailableIpsCounts = []int64{int64(ipCount)}
|
||||||
}
|
}
|
||||||
case "ip_ranges":
|
case "ip-ranges":
|
||||||
filters.IpRanges = filterValue
|
filters.IpRanges = filterValue
|
||||||
case "net_ids":
|
case "net-ids":
|
||||||
filters.NetIds = filterValue
|
filters.NetIds = filterValue
|
||||||
case "states":
|
case "states":
|
||||||
filters.States = filterValue
|
filters.States = filterValue
|
||||||
case "subnet_ids":
|
case "subnet-ids":
|
||||||
filters.SubnetIds = filterValue
|
filters.SubnetIds = filterValue
|
||||||
case "sub_region_names":
|
case "sub-region-names":
|
||||||
filters.SubregionNames = filterValue
|
filters.SubregionNames = filterValue
|
||||||
default:
|
default:
|
||||||
log.Printf("[Debug] Unknown Filter Name: %s.", name)
|
log.Printf("[Debug] Unknown Filter Name: %s.", name)
|
||||||
|
@ -65,23 +65,23 @@ func buildOMIFilters(input map[string]string) oapi.FiltersImage {
|
||||||
filterValue := []string{v}
|
filterValue := []string{v}
|
||||||
|
|
||||||
switch name := k; name {
|
switch name := k; name {
|
||||||
case "account_aliases":
|
case "account-aliases":
|
||||||
filters.AccountAliases = filterValue
|
filters.AccountAliases = filterValue
|
||||||
case "account_ids":
|
case "account-ids":
|
||||||
filters.AccountIds = filterValue
|
filters.AccountIds = filterValue
|
||||||
case "architectures":
|
case "architectures":
|
||||||
filters.Architectures = filterValue
|
filters.Architectures = filterValue
|
||||||
case "image_ids":
|
case "image-ids":
|
||||||
filters.ImageIds = filterValue
|
filters.ImageIds = filterValue
|
||||||
case "image_names":
|
case "image-names":
|
||||||
filters.ImageNames = filterValue
|
filters.ImageNames = filterValue
|
||||||
case "image_types":
|
case "image-types":
|
||||||
filters.ImageTypes = filterValue
|
filters.ImageTypes = filterValue
|
||||||
case "virtualization_types":
|
case "virtualization-types":
|
||||||
filters.VirtualizationTypes = filterValue
|
filters.VirtualizationTypes = filterValue
|
||||||
case "root_device_types":
|
case "root-device-types":
|
||||||
filters.RootDeviceTypes = filterValue
|
filters.RootDeviceTypes = filterValue
|
||||||
case "block_device_mapping_volume_type":
|
case "block-device-mapping-volume-type":
|
||||||
filters.BlockDeviceMappingVolumeType = filterValue
|
filters.BlockDeviceMappingVolumeType = filterValue
|
||||||
//Some params are missing.
|
//Some params are missing.
|
||||||
default:
|
default:
|
||||||
|
@ -90,3 +90,68 @@ func buildOMIFilters(input map[string]string) oapi.FiltersImage {
|
||||||
}
|
}
|
||||||
return filters
|
return filters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildSecurityGroupFilters(input map[string]string) oapi.FiltersSecurityGroup {
|
||||||
|
var filters oapi.FiltersSecurityGroup
|
||||||
|
for k, v := range input {
|
||||||
|
filterValue := []string{v}
|
||||||
|
|
||||||
|
switch name := k; name {
|
||||||
|
case "account-ids":
|
||||||
|
filters.AccountIds = filterValue
|
||||||
|
case "descriptions":
|
||||||
|
filters.Descriptions = filterValue
|
||||||
|
case "inbound-rule-account-ids":
|
||||||
|
filters.InboundRuleAccountIds = filterValue
|
||||||
|
case "inbound-rule-from-port-ranges":
|
||||||
|
if val, err := strconv.Atoi(v); err == nil {
|
||||||
|
filters.InboundRuleFromPortRanges = []int64{int64(val)}
|
||||||
|
}
|
||||||
|
case "inbound-rule-ip-ranges":
|
||||||
|
filters.InboundRuleIpRanges = filterValue
|
||||||
|
case "inbound-rule-protocols":
|
||||||
|
filters.InboundRuleProtocols = filterValue
|
||||||
|
case "inbound-rule-security-group-ids":
|
||||||
|
filters.InboundRuleSecurityGroupIds = filterValue
|
||||||
|
case "inbound-rule-security-group-names":
|
||||||
|
filters.InboundRuleSecurityGroupNames = filterValue
|
||||||
|
case "inbound-rule-to-port-ranges":
|
||||||
|
if val, err := strconv.Atoi(v); err == nil {
|
||||||
|
filters.InboundRuleToPortRanges = []int64{int64(val)}
|
||||||
|
}
|
||||||
|
case "net-ids":
|
||||||
|
filters.NetIds = filterValue
|
||||||
|
|
||||||
|
case "outbound-rule-account-ids":
|
||||||
|
filters.OutboundRuleAccountIds = filterValue
|
||||||
|
case "outbound-rule-from-port-ranges":
|
||||||
|
if val, err := strconv.Atoi(v); err == nil {
|
||||||
|
filters.OutboundRuleFromPortRanges = []int64{int64(val)}
|
||||||
|
}
|
||||||
|
case "outbound-rule-ip-ranges":
|
||||||
|
filters.OutboundRuleIpRanges = filterValue
|
||||||
|
case "outbound-rule-protocols":
|
||||||
|
filters.OutboundRuleProtocols = filterValue
|
||||||
|
case "outbound-rule-security-group-ids":
|
||||||
|
filters.OutboundRuleSecurityGroupIds = filterValue
|
||||||
|
case "outbound-rule-security-group-names":
|
||||||
|
filters.OutboundRuleSecurityGroupNames = filterValue
|
||||||
|
case "outbound-rule-to-port-ranges":
|
||||||
|
if val, err := strconv.Atoi(v); err == nil {
|
||||||
|
filters.OutboundRuleToPortRanges = []int64{int64(val)}
|
||||||
|
}
|
||||||
|
case "security-group-ids":
|
||||||
|
filters.SecurityGroupIds = filterValue
|
||||||
|
case "security-group-names":
|
||||||
|
filters.SecurityGroupNames = filterValue
|
||||||
|
case "tags-keys":
|
||||||
|
filters.TagKeys = filterValue
|
||||||
|
case "tags-values":
|
||||||
|
filters.TagValues = filterValue
|
||||||
|
//Some params are missing.
|
||||||
|
default:
|
||||||
|
log.Printf("[Debug] Unknown Filter Name: %s.", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filters
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (d *NetFilterOptions) Empty() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SecurityGroupFilterOptions struct {
|
type SecurityGroupFilterOptions struct {
|
||||||
Filters map[*string]*string
|
Filters map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *SecurityGroupFilterOptions) Empty() bool {
|
func (d *SecurityGroupFilterOptions) Empty() bool {
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/common"
|
||||||
|
"github.com/outscale/osc-go/oapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stateRefreshFunc func() (string, error)
|
||||||
|
|
||||||
|
func waitForSecurityGroup(conn *oapi.Client, securityGroupID string) error {
|
||||||
|
errCh := make(chan error, 1)
|
||||||
|
go waitForState(errCh, "exists", securityGroupWaitFunc(conn, securityGroupID))
|
||||||
|
err := <-errCh
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForState(errCh chan<- error, target string, refresh stateRefreshFunc) error {
|
||||||
|
err := common.Retry(2, 2, 0, func(_ uint) (bool, error) {
|
||||||
|
state, err := refresh()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
} else if state == target {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
errCh <- err
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func securityGroupWaitFunc(conn *oapi.Client, id string) stateRefreshFunc {
|
||||||
|
return func() (string, error) {
|
||||||
|
log.Printf("[Debug] Check if SG with id %s exists", id)
|
||||||
|
resp, err := conn.POST_ReadSecurityGroups(oapi.ReadSecurityGroupsRequest{
|
||||||
|
Filters: oapi.FiltersSecurityGroup{
|
||||||
|
SecurityGroupIds: []string{id},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Printf("[Debug] Read Response %+v", resp.OK)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.OK == nil {
|
||||||
|
return "", fmt.Errorf("Security Group with ID %s. Not Found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.OK.SecurityGroups) == 0 {
|
||||||
|
return "waiting", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "exists", nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/common/uuid"
|
||||||
|
"github.com/hashicorp/packer/helper/communicator"
|
||||||
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"github.com/outscale/osc-go/oapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepSecurityGroup struct {
|
||||||
|
CommConfig *communicator.Config
|
||||||
|
SecurityGroupFilter SecurityGroupFilterOptions
|
||||||
|
SecurityGroupIds []string
|
||||||
|
TemporarySGSourceCidr string
|
||||||
|
|
||||||
|
createdGroupId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepSecurityGroup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
oapiconn := state.Get("oapi").(*oapi.Client)
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
netId := state.Get("net_id").(string)
|
||||||
|
|
||||||
|
if len(s.SecurityGroupIds) > 0 {
|
||||||
|
resp, err := oapiconn.POST_ReadSecurityGroups(
|
||||||
|
oapi.ReadSecurityGroupsRequest{
|
||||||
|
Filters: oapi.FiltersSecurityGroup{
|
||||||
|
SecurityGroupIds: s.SecurityGroupIds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil || resp.OK == nil || len(resp.OK.SecurityGroups) <= 0 {
|
||||||
|
err := fmt.Errorf("Couldn't find specified security group: %s", err)
|
||||||
|
log.Printf("[DEBUG] %s", err.Error())
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Using specified security groups: %v", s.SecurityGroupIds)
|
||||||
|
state.Put("securityGroupIds", s.SecurityGroupIds)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.SecurityGroupFilter.Empty() {
|
||||||
|
|
||||||
|
params := oapi.ReadSecurityGroupsRequest{}
|
||||||
|
if netId != "" {
|
||||||
|
s.SecurityGroupFilter.Filters["net-id"] = netId
|
||||||
|
}
|
||||||
|
params.Filters = buildSecurityGroupFilters(s.SecurityGroupFilter.Filters)
|
||||||
|
|
||||||
|
log.Printf("Using SecurityGroup Filters %v", params)
|
||||||
|
|
||||||
|
sgResp, err := oapiconn.POST_ReadSecurityGroups(params)
|
||||||
|
if err != nil || sgResp.OK == nil {
|
||||||
|
err := fmt.Errorf("Couldn't find security groups for filter: %s", err)
|
||||||
|
log.Printf("[DEBUG] %s", err.Error())
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
securityGroupIds := []string{}
|
||||||
|
for _, sg := range sgResp.OK.SecurityGroups {
|
||||||
|
securityGroupIds = append(securityGroupIds, sg.SecurityGroupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Found Security Group(s): %s", strings.Join(securityGroupIds, ", ")))
|
||||||
|
state.Put("securityGroupIds", securityGroupIds)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
port := s.CommConfig.Port()
|
||||||
|
if port == 0 {
|
||||||
|
if s.CommConfig.Type != "none" {
|
||||||
|
panic("port must be set to a non-zero value.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the group
|
||||||
|
groupName := fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
|
||||||
|
ui.Say(fmt.Sprintf("Creating temporary security group for this instance: %s", groupName))
|
||||||
|
group := oapi.CreateSecurityGroupRequest{
|
||||||
|
SecurityGroupName: groupName,
|
||||||
|
Description: "Temporary group for Packer",
|
||||||
|
}
|
||||||
|
|
||||||
|
group.NetId = netId
|
||||||
|
|
||||||
|
groupResp, err := oapiconn.POST_CreateSecurityGroup(group)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(err.Error())
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the group ID so we can delete it later
|
||||||
|
s.createdGroupId = groupResp.OK.SecurityGroup.SecurityGroupId
|
||||||
|
|
||||||
|
// Wait for the security group become available for authorizing
|
||||||
|
log.Printf("[DEBUG] Waiting for temporary security group: %s", s.createdGroupId)
|
||||||
|
err = waitForSecurityGroup(oapiconn, s.createdGroupId)
|
||||||
|
if err == nil {
|
||||||
|
log.Printf("[DEBUG] Found security group %s", s.createdGroupId)
|
||||||
|
} else {
|
||||||
|
err := fmt.Errorf("Timed out waiting for security group %s: %s", s.createdGroupId, err)
|
||||||
|
log.Printf("[DEBUG] %s", err.Error())
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorize the SSH access for the security group
|
||||||
|
groupRules := oapi.CreateSecurityGroupRuleRequest{
|
||||||
|
SecurityGroupId: groupResp.OK.SecurityGroup.SecurityGroupId,
|
||||||
|
Flow: "Inbound",
|
||||||
|
Rules: []oapi.SecurityGroupRule{
|
||||||
|
oapi.SecurityGroupRule{
|
||||||
|
FromPortRange: int64(port),
|
||||||
|
ToPortRange: int64(port),
|
||||||
|
IpRanges: []string{s.TemporarySGSourceCidr},
|
||||||
|
IpProtocol: "tcp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf(
|
||||||
|
"Authorizing access to port %d from %s in the temporary security group...",
|
||||||
|
port, s.TemporarySGSourceCidr))
|
||||||
|
_, err = oapiconn.POST_CreateSecurityGroupRule(groupRules)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error authorizing temporary security group: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set some state data for use in future steps
|
||||||
|
state.Put("securityGroupIds", []string{s.createdGroupId})
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepSecurityGroup) Cleanup(state multistep.StateBag) {
|
||||||
|
if s.createdGroupId == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
oapiconn := state.Get("oapi").(*oapi.Client)
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
|
ui.Say("Deleting temporary security group...")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
_, err = oapiconn.POST_DeleteSecurityGroup(oapi.DeleteSecurityGroupRequest{SecurityGroupId: s.createdGroupId})
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Error deleting security group: %s", err)
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error cleaning up security group. Please delete the group manually: %s", s.createdGroupId))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue