github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/amazon/common/ami_config.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/hashicorp/packer/template/interpolate" 8 ) 9 10 // AMIConfig is for common configuration related to creating AMIs. 11 type AMIConfig struct { 12 AMIName string `mapstructure:"ami_name"` 13 AMIDescription string `mapstructure:"ami_description"` 14 AMIVirtType string `mapstructure:"ami_virtualization_type"` 15 AMIUsers []string `mapstructure:"ami_users"` 16 AMIGroups []string `mapstructure:"ami_groups"` 17 AMIProductCodes []string `mapstructure:"ami_product_codes"` 18 AMIRegions []string `mapstructure:"ami_regions"` 19 AMISkipRegionValidation bool `mapstructure:"skip_region_validation"` 20 AMITags TagMap `mapstructure:"tags"` 21 AMIENASupport bool `mapstructure:"ena_support"` 22 AMISriovNetSupport bool `mapstructure:"sriov_support"` 23 AMIForceDeregister bool `mapstructure:"force_deregister"` 24 AMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"` 25 AMIEncryptBootVolume bool `mapstructure:"encrypt_boot"` 26 AMIKmsKeyId string `mapstructure:"kms_key_id"` 27 AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"` 28 SnapshotTags TagMap `mapstructure:"snapshot_tags"` 29 SnapshotUsers []string `mapstructure:"snapshot_users"` 30 SnapshotGroups []string `mapstructure:"snapshot_groups"` 31 } 32 33 func stringInSlice(s []string, searchstr string) bool { 34 for _, item := range s { 35 if item == searchstr { 36 return true 37 } 38 } 39 return false 40 } 41 42 func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context) []error { 43 var errs []error 44 45 if c.AMIName == "" { 46 errs = append(errs, fmt.Errorf("ami_name must be specified")) 47 } 48 49 // Make sure that if we have region_kms_key_ids defined, 50 // the regions in region_kms_key_ids are also in ami_regions 51 if len(c.AMIRegionKMSKeyIDs) > 0 { 52 for kmsKeyRegion := range c.AMIRegionKMSKeyIDs { 53 if !stringInSlice(c.AMIRegions, kmsKeyRegion) { 54 errs = append(errs, fmt.Errorf("Region %s is in region_kms_key_ids but not in ami_regions", kmsKeyRegion)) 55 } 56 } 57 } 58 59 if len(c.AMIRegions) > 0 { 60 regionSet := make(map[string]struct{}) 61 regions := make([]string, 0, len(c.AMIRegions)) 62 63 for _, region := range c.AMIRegions { 64 // If we already saw the region, then don't look again 65 if _, ok := regionSet[region]; ok { 66 continue 67 } 68 69 // Mark that we saw the region 70 regionSet[region] = struct{}{} 71 72 if !c.AMISkipRegionValidation { 73 // Verify the region is real 74 if valid := ValidateRegion(region); !valid { 75 errs = append(errs, fmt.Errorf("Unknown region: %s", region)) 76 } 77 } 78 79 // Make sure that if we have region_kms_key_ids defined, 80 // the regions in ami_regions are also in region_kms_key_ids 81 if len(c.AMIRegionKMSKeyIDs) > 0 { 82 if _, ok := c.AMIRegionKMSKeyIDs[region]; !ok { 83 errs = append(errs, fmt.Errorf("Region %s is in ami_regions but not in region_kms_key_ids", region)) 84 } 85 } 86 if (accessConfig != nil) && (region == accessConfig.RawRegion) { 87 // make sure we don't try to copy to the region we originally 88 // create the AMI in. 89 log.Printf("Cannot copy AMI to AWS session region '%s', deleting it from `ami_regions`.", region) 90 continue 91 } 92 regions = append(regions, region) 93 } 94 95 c.AMIRegions = regions 96 } 97 98 if len(c.AMIUsers) > 0 && c.AMIEncryptBootVolume { 99 errs = append(errs, fmt.Errorf("Cannot share AMI with encrypted boot volume")) 100 } 101 102 if len(c.SnapshotUsers) > 0 { 103 if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume { 104 errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key")) 105 } 106 if len(c.AMIRegionKMSKeyIDs) > 0 { 107 for _, kmsKey := range c.AMIRegionKMSKeyIDs { 108 if len(kmsKey) == 0 { 109 errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key")) 110 } 111 } 112 } 113 } 114 115 if len(c.AMIName) < 3 || len(c.AMIName) > 128 { 116 errs = append(errs, fmt.Errorf("ami_name must be between 3 and 128 characters long")) 117 } 118 119 if c.AMIName != templateCleanAMIName(c.AMIName) { 120 errs = append(errs, fmt.Errorf("AMIName should only contain "+ 121 "alphanumeric characters, parentheses (()), square brackets ([]), spaces "+ 122 "( ), periods (.), slashes (/), dashes (-), single quotes ('), at-signs "+ 123 "(@), or underscores(_). You can use the `clean_ami_name` template "+ 124 "filter to automatically clean your ami name.")) 125 } 126 127 if len(errs) > 0 { 128 return errs 129 } 130 131 return nil 132 }