github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/vcd/resource_vcd_vapp.go (about)

     1  package vcd
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/terraform/helper/resource"
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  	types "github.com/ukcloud/govcloudair/types/v56"
    10  )
    11  
    12  func resourceVcdVApp() *schema.Resource {
    13  	return &schema.Resource{
    14  		Create: resourceVcdVAppCreate,
    15  		Update: resourceVcdVAppUpdate,
    16  		Read:   resourceVcdVAppRead,
    17  		Delete: resourceVcdVAppDelete,
    18  
    19  		Schema: map[string]*schema.Schema{
    20  			"name": &schema.Schema{
    21  				Type:     schema.TypeString,
    22  				Required: true,
    23  				ForceNew: true,
    24  			},
    25  
    26  			"template_name": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Required: true,
    29  				ForceNew: true,
    30  			},
    31  
    32  			"catalog_name": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Required: true,
    35  			},
    36  
    37  			"network_href": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Optional: true,
    40  			},
    41  
    42  			"network_name": &schema.Schema{
    43  				Type:     schema.TypeString,
    44  				Required: true,
    45  				ForceNew: true,
    46  			},
    47  			"memory": &schema.Schema{
    48  				Type:     schema.TypeInt,
    49  				Optional: true,
    50  			},
    51  			"cpus": &schema.Schema{
    52  				Type:     schema.TypeInt,
    53  				Optional: true,
    54  			},
    55  			"ip": &schema.Schema{
    56  				Type:     schema.TypeString,
    57  				Optional: true,
    58  				Computed: true,
    59  			},
    60  			"initscript": &schema.Schema{
    61  				Type:     schema.TypeString,
    62  				Optional: true,
    63  				ForceNew: true,
    64  			},
    65  			"metadata": &schema.Schema{
    66  				Type:     schema.TypeMap,
    67  				Optional: true,
    68  			},
    69  			"href": &schema.Schema{
    70  				Type:     schema.TypeString,
    71  				Optional: true,
    72  				Computed: true,
    73  			},
    74  			"power_on": &schema.Schema{
    75  				Type:     schema.TypeBool,
    76  				Optional: true,
    77  				Default:  true,
    78  			},
    79  		},
    80  	}
    81  }
    82  
    83  func resourceVcdVAppCreate(d *schema.ResourceData, meta interface{}) error {
    84  	vcdClient := meta.(*VCDClient)
    85  
    86  	catalog, err := vcdClient.Org.FindCatalog(d.Get("catalog_name").(string))
    87  	if err != nil {
    88  		return fmt.Errorf("Error finding catalog: %#v", err)
    89  	}
    90  
    91  	catalogitem, err := catalog.FindCatalogItem(d.Get("template_name").(string))
    92  	if err != nil {
    93  		return fmt.Errorf("Error finding catelog item: %#v", err)
    94  	}
    95  
    96  	vapptemplate, err := catalogitem.GetVAppTemplate()
    97  	if err != nil {
    98  		return fmt.Errorf("Error finding VAppTemplate: %#v", err)
    99  	}
   100  
   101  	log.Printf("[DEBUG] VAppTemplate: %#v", vapptemplate)
   102  	var networkHref string
   103  	net, err := vcdClient.OrgVdc.FindVDCNetwork(d.Get("network_name").(string))
   104  	if err != nil {
   105  		return fmt.Errorf("Error finding OrgVCD Network: %#v", err)
   106  	}
   107  	if attr, ok := d.GetOk("network_href"); ok {
   108  		networkHref = attr.(string)
   109  	} else {
   110  		networkHref = net.OrgVDCNetwork.HREF
   111  	}
   112  	// vapptemplate := govcd.NewVAppTemplate(&vcdClient.Client)
   113  	//
   114  	createvapp := &types.InstantiateVAppTemplateParams{
   115  		Ovf:   "http://schemas.dmtf.org/ovf/envelope/1",
   116  		Xmlns: "http://www.vmware.com/vcloud/v1.5",
   117  		Name:  d.Get("name").(string),
   118  		InstantiationParams: &types.InstantiationParams{
   119  			NetworkConfigSection: &types.NetworkConfigSection{
   120  				Info: "Configuration parameters for logical networks",
   121  				NetworkConfig: &types.VAppNetworkConfiguration{
   122  					NetworkName: d.Get("network_name").(string),
   123  					Configuration: &types.NetworkConfiguration{
   124  						ParentNetwork: &types.Reference{
   125  							HREF: networkHref,
   126  						},
   127  						FenceMode: "bridged",
   128  					},
   129  				},
   130  			},
   131  		},
   132  		Source: &types.Reference{
   133  			HREF: vapptemplate.VAppTemplate.HREF,
   134  		},
   135  	}
   136  
   137  	err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   138  		e := vcdClient.OrgVdc.InstantiateVAppTemplate(createvapp)
   139  
   140  		if e != nil {
   141  			return resource.RetryableError(fmt.Errorf("Error: %#v", e))
   142  		}
   143  
   144  		e = vcdClient.OrgVdc.Refresh()
   145  		if e != nil {
   146  			return resource.RetryableError(fmt.Errorf("Error: %#v", e))
   147  		}
   148  		return nil
   149  	})
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Get("name").(string))
   155  
   156  	err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   157  		task, err := vapp.ChangeVMName(d.Get("name").(string))
   158  		if err != nil {
   159  			return resource.RetryableError(fmt.Errorf("Error with vm name change: %#v", err))
   160  		}
   161  
   162  		return resource.RetryableError(task.WaitTaskCompletion())
   163  	})
   164  	if err != nil {
   165  		return fmt.Errorf("Error changing vmname: %#v", err)
   166  	}
   167  
   168  	err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   169  		task, err := vapp.ChangeNetworkConfig(d.Get("network_name").(string), d.Get("ip").(string))
   170  		if err != nil {
   171  			return resource.RetryableError(fmt.Errorf("Error with Networking change: %#v", err))
   172  		}
   173  		return resource.RetryableError(task.WaitTaskCompletion())
   174  	})
   175  	if err != nil {
   176  		return fmt.Errorf("Error changing network: %#v", err)
   177  	}
   178  
   179  	if initscript, ok := d.GetOk("initscript"); ok {
   180  		err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   181  			task, err := vapp.RunCustomizationScript(d.Get("name").(string), initscript.(string))
   182  			if err != nil {
   183  				return resource.RetryableError(fmt.Errorf("Error with setting init script: %#v", err))
   184  			}
   185  			return resource.RetryableError(task.WaitTaskCompletion())
   186  		})
   187  		if err != nil {
   188  			return fmt.Errorf("Error completing tasks: %#v", err)
   189  		}
   190  	}
   191  
   192  	d.SetId(d.Get("name").(string))
   193  
   194  	return resourceVcdVAppUpdate(d, meta)
   195  }
   196  
   197  func resourceVcdVAppUpdate(d *schema.ResourceData, meta interface{}) error {
   198  	vcdClient := meta.(*VCDClient)
   199  	vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id())
   200  
   201  	if err != nil {
   202  		return fmt.Errorf("Error finding VApp: %#v", err)
   203  	}
   204  
   205  	status, err := vapp.GetStatus()
   206  	if err != nil {
   207  		return fmt.Errorf("Error getting VApp status: %#v", err)
   208  	}
   209  
   210  	if d.HasChange("metadata") {
   211  		oraw, nraw := d.GetChange("metadata")
   212  		metadata := oraw.(map[string]interface{})
   213  		for k := range metadata {
   214  			task, err := vapp.DeleteMetadata(k)
   215  			if err != nil {
   216  				return fmt.Errorf("Error deleting metadata: %#v", err)
   217  			}
   218  			err = task.WaitTaskCompletion()
   219  			if err != nil {
   220  				return fmt.Errorf("Error completing tasks: %#v", err)
   221  			}
   222  		}
   223  		metadata = nraw.(map[string]interface{})
   224  		for k, v := range metadata {
   225  			task, err := vapp.AddMetadata(k, v.(string))
   226  			if err != nil {
   227  				return fmt.Errorf("Error adding metadata: %#v", err)
   228  			}
   229  			err = task.WaitTaskCompletion()
   230  			if err != nil {
   231  				return fmt.Errorf("Error completing tasks: %#v", err)
   232  			}
   233  		}
   234  
   235  	}
   236  
   237  	if d.HasChange("memory") || d.HasChange("cpus") || d.HasChange("power_on") {
   238  		if status != "POWERED_OFF" {
   239  			task, err := vapp.PowerOff()
   240  			if err != nil {
   241  				return fmt.Errorf("Error Powering Off: %#v", err)
   242  			}
   243  			err = task.WaitTaskCompletion()
   244  			if err != nil {
   245  				return fmt.Errorf("Error completing tasks: %#v", err)
   246  			}
   247  		}
   248  
   249  		if d.HasChange("memory") {
   250  			err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   251  				task, err := vapp.ChangeMemorySize(d.Get("memory").(int))
   252  				if err != nil {
   253  					return resource.RetryableError(fmt.Errorf("Error changing memory size: %#v", err))
   254  				}
   255  
   256  				return resource.RetryableError(task.WaitTaskCompletion())
   257  			})
   258  			if err != nil {
   259  				return err
   260  			}
   261  		}
   262  
   263  		if d.HasChange("cpus") {
   264  			err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   265  				task, err := vapp.ChangeCPUcount(d.Get("cpus").(int))
   266  				if err != nil {
   267  					return resource.RetryableError(fmt.Errorf("Error changing cpu count: %#v", err))
   268  				}
   269  
   270  				return resource.RetryableError(task.WaitTaskCompletion())
   271  			})
   272  			if err != nil {
   273  				return fmt.Errorf("Error completing task: %#v", err)
   274  			}
   275  		}
   276  
   277  		if d.Get("power_on").(bool) {
   278  			task, err := vapp.PowerOn()
   279  			if err != nil {
   280  				return fmt.Errorf("Error Powering Up: %#v", err)
   281  			}
   282  			err = task.WaitTaskCompletion()
   283  			if err != nil {
   284  				return fmt.Errorf("Error completing tasks: %#v", err)
   285  			}
   286  		}
   287  
   288  	}
   289  
   290  	return resourceVcdVAppRead(d, meta)
   291  }
   292  
   293  func resourceVcdVAppRead(d *schema.ResourceData, meta interface{}) error {
   294  	vcdClient := meta.(*VCDClient)
   295  
   296  	err := vcdClient.OrgVdc.Refresh()
   297  	if err != nil {
   298  		return fmt.Errorf("Error refreshing vdc: %#v", err)
   299  	}
   300  
   301  	_, err = vcdClient.OrgVdc.FindVAppByName(d.Id())
   302  	if err != nil {
   303  		log.Printf("[DEBUG] Unable to find vapp. Removing from tfstate")
   304  		d.SetId("")
   305  		return nil
   306  	}
   307  
   308  	ip, err := getVAppIPAddress(d, meta)
   309  	if err != nil {
   310  		return err
   311  	}
   312  	d.Set("ip", ip)
   313  
   314  	return nil
   315  }
   316  
   317  func getVAppIPAddress(d *schema.ResourceData, meta interface{}) (string, error) {
   318  	vcdClient := meta.(*VCDClient)
   319  	var ip string
   320  
   321  	err := retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   322  		err := vcdClient.OrgVdc.Refresh()
   323  		if err != nil {
   324  			return resource.RetryableError(fmt.Errorf("Error refreshing vdc: %#v", err))
   325  		}
   326  		vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id())
   327  		if err != nil {
   328  			return resource.RetryableError(fmt.Errorf("Unable to find vapp."))
   329  		}
   330  		ip = vapp.VApp.Children.VM[0].NetworkConnectionSection.NetworkConnection.IPAddress
   331  		if ip == "" {
   332  			return resource.RetryableError(fmt.Errorf("Timeout: VM did not aquire IP address"))
   333  		}
   334  		return nil
   335  	})
   336  
   337  	return ip, err
   338  }
   339  
   340  func resourceVcdVAppDelete(d *schema.ResourceData, meta interface{}) error {
   341  	vcdClient := meta.(*VCDClient)
   342  	vapp, err := vcdClient.OrgVdc.FindVAppByName(d.Id())
   343  
   344  	if err != nil {
   345  		return fmt.Errorf("error finding vapp: %s", err)
   346  	}
   347  
   348  	if err != nil {
   349  		return fmt.Errorf("Error getting VApp status: %#v", err)
   350  	}
   351  
   352  	_ = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   353  		task, err := vapp.Undeploy()
   354  		if err != nil {
   355  			return resource.RetryableError(fmt.Errorf("Error undeploying: %#v", err))
   356  		}
   357  
   358  		return resource.RetryableError(task.WaitTaskCompletion())
   359  	})
   360  
   361  	err = retryCall(vcdClient.MaxRetryTimeout, func() *resource.RetryError {
   362  		task, err := vapp.Delete()
   363  		if err != nil {
   364  			return resource.RetryableError(fmt.Errorf("Error deleting: %#v", err))
   365  		}
   366  
   367  		return resource.RetryableError(task.WaitTaskCompletion())
   368  	})
   369  
   370  	return err
   371  }