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  }