forked from hashicorp/packer
/
config.go
155 lines (137 loc) · 4.77 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package classic
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"os"
"regexp"
"time"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Comm communicator.Config `mapstructure:",squash"`
attribs map[string]interface{}
// Access config overrides
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
IdentityDomain string `mapstructure:"identity_domain"`
APIEndpoint string `mapstructure:"api_endpoint"`
apiEndpointURL *url.URL
// Image
ImageName string `mapstructure:"image_name"`
Shape string `mapstructure:"shape"`
SourceImageList string `mapstructure:"source_image_list"`
SnapshotTimeout time.Duration `mapstructure:"snapshot_timeout"`
DestImageList string `mapstructure:"dest_image_list"`
// Attributes and Attributes file are both optional and mutually exclusive.
Attributes string `mapstructure:"attributes"`
AttributesFile string `mapstructure:"attributes_file"`
// Optional; if you don't enter anything, the image list description
// will read "Packer-built image list"
DestImageListDescription string `mapstructure:"image_description"`
// Optional. Describes what computers are allowed to reach your instance
// via SSH. This whitelist must contain the computer you're running Packer
// from. It defaults to public-internet, meaning that you can SSH into your
// instance from anywhere as long as you have the right keys
SSHSourceList string `mapstructure:"ssh_source_list"`
ctx interpolate.Context
}
func NewConfig(raws ...interface{}) (*Config, error) {
c := &Config{}
// Decode from template
err := config.Decode(c, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &c.ctx,
}, raws...)
if err != nil {
return nil, fmt.Errorf("Failed to mapstructure Config: %+v", err)
}
c.apiEndpointURL, err = url.Parse(c.APIEndpoint)
if err != nil {
return nil, fmt.Errorf("Error parsing API Endpoint: %s", err)
}
// Set default source list
if c.SSHSourceList == "" {
c.SSHSourceList = "seciplist:/oracle/public/public-internet"
}
// Use default oracle username with sudo privileges
if c.Comm.SSHUsername == "" {
c.Comm.SSHUsername = "opc"
}
if c.SnapshotTimeout == 0 {
c.SnapshotTimeout = 20 * time.Minute
}
// Validate that all required fields are present
var errs *packer.MultiError
required := map[string]string{
"username": c.Username,
"password": c.Password,
"api_endpoint": c.APIEndpoint,
"identity_domain": c.IdentityDomain,
"source_image_list": c.SourceImageList,
"dest_image_list": c.DestImageList,
"shape": c.Shape,
}
for k, v := range required {
if v == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("You must specify a %s.", k))
}
}
// Object names can contain only alphanumeric characters, hyphens, underscores, and periods
reValidObject := regexp.MustCompile("^[a-zA-Z0-9-._/]+$")
var objectValidation = []struct {
name string
value string
}{
{"dest_image_list", c.DestImageList},
{"image_name", c.ImageName},
}
for _, ov := range objectValidation {
if !reValidObject.MatchString(ov.value) {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("%s can contain only alphanumeric characters, hyphens, underscores, and periods.", ov.name))
}
}
if c.Attributes != "" && c.AttributesFile != "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified."))
} else if c.AttributesFile != "" {
if _, err := os.Stat(c.AttributesFile); err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("attributes_file not found: %s", c.AttributesFile))
}
}
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packer.MultiErrorAppend(errs, es...)
}
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
// unpack attributes from json into config
var data map[string]interface{}
if c.Attributes != "" {
err := json.Unmarshal([]byte(c.Attributes), &data)
if err != nil {
err = fmt.Errorf("Problem parsing json from attributes: %s", err)
packer.MultiErrorAppend(errs, err)
}
c.attribs = data
} else if c.AttributesFile != "" {
fidata, err := ioutil.ReadFile(c.AttributesFile)
if err != nil {
err = fmt.Errorf("Problem reading attributes_file: %s", err)
packer.MultiErrorAppend(errs, err)
}
err = json.Unmarshal(fidata, &data)
c.attribs = data
if err != nil {
err = fmt.Errorf("Problem parsing json from attributes_file: %s", err)
packer.MultiErrorAppend(errs, err)
}
c.attribs = data
}
return c, nil
}