feature: bsusurrogate, add security group step

This commit is contained in:
Marin Salinas 2019-02-01 15:20:47 -06:00 committed by Megan Marsh
parent cef9a4b9fd
commit 5ef3e81234
5 changed files with 324 additions and 19 deletions

View File

@ -158,6 +158,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Comm: &b.config.RunConfig.Comm,
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)

View File

@ -12,19 +12,19 @@ func buildNetFilters(input map[string]string) oapi.FiltersNet {
for k, v := range input {
filterValue := []string{v}
switch name := k; name {
case "ip_range":
case "ip-range":
filters.IpRanges = filterValue
case "dhcp_options_set_id":
case "dhcp-options-set-id":
filters.DhcpOptionsSetIds = filterValue
case "is_default":
case "is-default":
if isDefault, err := strconv.ParseBool(v); err == nil {
filters.IsDefault = isDefault
}
case "state":
filters.States = filterValue
case "tag_key":
case "tag-key":
filters.TagKeys = filterValue
case "tag_value":
case "tag-value":
filters.TagValues = filterValue
default:
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 {
filterValue := []string{v}
switch name := k; name {
case "available_ips_counts":
case "available-ips-counts":
if ipCount, err := strconv.Atoi(v); err == nil {
filters.AvailableIpsCounts = []int64{int64(ipCount)}
}
case "ip_ranges":
case "ip-ranges":
filters.IpRanges = filterValue
case "net_ids":
case "net-ids":
filters.NetIds = filterValue
case "states":
filters.States = filterValue
case "subnet_ids":
case "subnet-ids":
filters.SubnetIds = filterValue
case "sub_region_names":
case "sub-region-names":
filters.SubregionNames = filterValue
default:
log.Printf("[Debug] Unknown Filter Name: %s.", name)
@ -65,23 +65,23 @@ func buildOMIFilters(input map[string]string) oapi.FiltersImage {
filterValue := []string{v}
switch name := k; name {
case "account_aliases":
case "account-aliases":
filters.AccountAliases = filterValue
case "account_ids":
case "account-ids":
filters.AccountIds = filterValue
case "architectures":
filters.Architectures = filterValue
case "image_ids":
case "image-ids":
filters.ImageIds = filterValue
case "image_names":
case "image-names":
filters.ImageNames = filterValue
case "image_types":
case "image-types":
filters.ImageTypes = filterValue
case "virtualization_types":
case "virtualization-types":
filters.VirtualizationTypes = filterValue
case "root_device_types":
case "root-device-types":
filters.RootDeviceTypes = filterValue
case "block_device_mapping_volume_type":
case "block-device-mapping-volume-type":
filters.BlockDeviceMappingVolumeType = filterValue
//Some params are missing.
default:
@ -90,3 +90,68 @@ func buildOMIFilters(input map[string]string) oapi.FiltersImage {
}
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
}

View File

@ -48,7 +48,7 @@ func (d *NetFilterOptions) Empty() bool {
}
type SecurityGroupFilterOptions struct {
Filters map[*string]*string
Filters map[string]string
}
func (d *SecurityGroupFilterOptions) Empty() bool {

View File

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

View File

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