github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/ignition/resource_ignition_config.go (about) 1 package ignition 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "github.com/hashicorp/terraform/helper/schema" 8 9 "github.com/coreos/ignition/config/types" 10 ) 11 12 var configReferenceResource = &schema.Resource{ 13 Schema: map[string]*schema.Schema{ 14 "source": &schema.Schema{ 15 Type: schema.TypeString, 16 ForceNew: true, 17 Required: true, 18 }, 19 "verification": &schema.Schema{ 20 Type: schema.TypeString, 21 ForceNew: true, 22 Optional: true, 23 }, 24 }, 25 } 26 27 func resourceConfig() *schema.Resource { 28 return &schema.Resource{ 29 Exists: resourceIgnitionFileExists, 30 Read: resourceIgnitionFileRead, 31 Schema: map[string]*schema.Schema{ 32 "disks": &schema.Schema{ 33 Type: schema.TypeList, 34 Optional: true, 35 Elem: &schema.Schema{Type: schema.TypeString}, 36 }, 37 "arrays": &schema.Schema{ 38 Type: schema.TypeList, 39 Optional: true, 40 Elem: &schema.Schema{Type: schema.TypeString}, 41 }, 42 "filesystems": &schema.Schema{ 43 Type: schema.TypeList, 44 Optional: true, 45 Elem: &schema.Schema{Type: schema.TypeString}, 46 }, 47 "files": &schema.Schema{ 48 Type: schema.TypeList, 49 Optional: true, 50 Elem: &schema.Schema{Type: schema.TypeString}, 51 }, 52 "systemd": &schema.Schema{ 53 Type: schema.TypeList, 54 Optional: true, 55 Elem: &schema.Schema{Type: schema.TypeString}, 56 }, 57 "networkd": &schema.Schema{ 58 Type: schema.TypeList, 59 Optional: true, 60 Elem: &schema.Schema{Type: schema.TypeString}, 61 }, 62 "users": &schema.Schema{ 63 Type: schema.TypeList, 64 Optional: true, 65 Elem: &schema.Schema{Type: schema.TypeString}, 66 }, 67 "groups": &schema.Schema{ 68 Type: schema.TypeList, 69 Optional: true, 70 Elem: &schema.Schema{Type: schema.TypeString}, 71 }, 72 "replace": &schema.Schema{ 73 Type: schema.TypeList, 74 ForceNew: true, 75 Optional: true, 76 MaxItems: 1, 77 Elem: configReferenceResource, 78 }, 79 "append": &schema.Schema{ 80 Type: schema.TypeList, 81 ForceNew: true, 82 Optional: true, 83 Elem: configReferenceResource, 84 }, 85 "rendered": &schema.Schema{ 86 Type: schema.TypeString, 87 Computed: true, 88 }, 89 }, 90 } 91 } 92 93 func resourceIgnitionFileRead(d *schema.ResourceData, meta interface{}) error { 94 rendered, err := renderConfig(d, meta.(*cache)) 95 if err != nil { 96 return err 97 } 98 99 if err := d.Set("rendered", rendered); err != nil { 100 return err 101 } 102 103 d.SetId(hash(rendered)) 104 return nil 105 } 106 107 func resourceIgnitionFileExists(d *schema.ResourceData, meta interface{}) (bool, error) { 108 rendered, err := renderConfig(d, meta.(*cache)) 109 if err != nil { 110 return false, err 111 } 112 113 return hash(rendered) == d.Id(), nil 114 } 115 116 func renderConfig(d *schema.ResourceData, c *cache) (string, error) { 117 i, err := buildConfig(d, c) 118 if err != nil { 119 return "", err 120 } 121 122 bytes, err := json.MarshalIndent(i, " ", " ") 123 124 if err != nil { 125 return "", err 126 } 127 128 return string(bytes), nil 129 } 130 131 func buildConfig(d *schema.ResourceData, c *cache) (*types.Config, error) { 132 var err error 133 config := &types.Config{} 134 config.Ignition, err = buildIgnition(d) 135 if err != nil { 136 return nil, err 137 } 138 139 config.Storage, err = buildStorage(d, c) 140 if err != nil { 141 return nil, err 142 } 143 144 config.Systemd, err = buildSystemd(d, c) 145 if err != nil { 146 return nil, err 147 } 148 149 config.Networkd, err = buildNetworkd(d, c) 150 if err != nil { 151 return nil, err 152 } 153 154 config.Passwd, err = buildPasswd(d, c) 155 if err != nil { 156 return nil, err 157 } 158 159 return config, nil 160 } 161 162 func buildIgnition(d *schema.ResourceData) (types.Ignition, error) { 163 var err error 164 165 i := types.Ignition{} 166 i.Version.UnmarshalJSON([]byte(`"2.0.0"`)) 167 168 rr := d.Get("replace.0").(map[string]interface{}) 169 if len(rr) != 0 { 170 i.Config.Replace, err = buildConfigReference(rr) 171 if err != nil { 172 return i, err 173 } 174 } 175 176 ar := d.Get("append").([]interface{}) 177 if len(ar) != 0 { 178 for _, rr := range ar { 179 r, err := buildConfigReference(rr.(map[string]interface{})) 180 if err != nil { 181 return i, err 182 } 183 184 i.Config.Append = append(i.Config.Append, *r) 185 } 186 } 187 188 return i, nil 189 } 190 191 func buildConfigReference(raw map[string]interface{}) (*types.ConfigReference, error) { 192 r := &types.ConfigReference{} 193 194 src, err := buildURL(raw["source"].(string)) 195 if err != nil { 196 return nil, err 197 } 198 199 r.Source = src 200 201 hash, err := buildHash(raw["verification"].(string)) 202 if err != nil { 203 return nil, err 204 } 205 206 r.Verification.Hash = &hash 207 208 return r, nil 209 } 210 211 func buildStorage(d *schema.ResourceData, c *cache) (types.Storage, error) { 212 storage := types.Storage{} 213 214 for _, id := range d.Get("disks").([]interface{}) { 215 d, ok := c.disks[id.(string)] 216 if !ok { 217 return storage, fmt.Errorf("invalid disk %q, unknown disk id", id) 218 } 219 220 storage.Disks = append(storage.Disks, *d) 221 } 222 223 for _, id := range d.Get("arrays").([]interface{}) { 224 a, ok := c.arrays[id.(string)] 225 if !ok { 226 return storage, fmt.Errorf("invalid raid %q, unknown raid id", id) 227 } 228 229 storage.Arrays = append(storage.Arrays, *a) 230 } 231 232 for _, id := range d.Get("filesystems").([]interface{}) { 233 f, ok := c.filesystems[id.(string)] 234 if !ok { 235 return storage, fmt.Errorf("invalid filesystem %q, unknown filesystem id", id) 236 } 237 238 storage.Filesystems = append(storage.Filesystems, *f) 239 } 240 241 for _, id := range d.Get("files").([]interface{}) { 242 f, ok := c.files[id.(string)] 243 if !ok { 244 return storage, fmt.Errorf("invalid file %q, unknown file id", id) 245 } 246 247 storage.Files = append(storage.Files, *f) 248 } 249 250 return storage, nil 251 252 } 253 254 func buildSystemd(d *schema.ResourceData, c *cache) (types.Systemd, error) { 255 systemd := types.Systemd{} 256 257 for _, id := range d.Get("systemd").([]interface{}) { 258 u, ok := c.systemdUnits[id.(string)] 259 if !ok { 260 return systemd, fmt.Errorf("invalid systemd unit %q, unknown systemd unit id", id) 261 } 262 263 systemd.Units = append(systemd.Units, *u) 264 } 265 266 return systemd, nil 267 268 } 269 270 func buildNetworkd(d *schema.ResourceData, c *cache) (types.Networkd, error) { 271 networkd := types.Networkd{} 272 273 for _, id := range d.Get("networkd").([]interface{}) { 274 u, ok := c.networkdUnits[id.(string)] 275 if !ok { 276 return networkd, fmt.Errorf("invalid networkd unit %q, unknown networkd unit id", id) 277 } 278 279 networkd.Units = append(networkd.Units, *u) 280 } 281 282 return networkd, nil 283 } 284 285 func buildPasswd(d *schema.ResourceData, c *cache) (types.Passwd, error) { 286 passwd := types.Passwd{} 287 288 for _, id := range d.Get("users").([]interface{}) { 289 u, ok := c.users[id.(string)] 290 if !ok { 291 return passwd, fmt.Errorf("invalid user %q, unknown user id", id) 292 } 293 294 passwd.Users = append(passwd.Users, *u) 295 } 296 297 for _, id := range d.Get("groups").([]interface{}) { 298 g, ok := c.groups[id.(string)] 299 if !ok { 300 return passwd, fmt.Errorf("invalid group %q, unknown group id", id) 301 } 302 303 passwd.Groups = append(passwd.Groups, *g) 304 } 305 306 return passwd, nil 307 308 }