Skip to content

Commit

Permalink
new vesrion with support for using external links with box format
Browse files Browse the repository at this point in the history
  • Loading branch information
IuriiMedvedev committed May 22, 2017
1 parent 961d961 commit 7da910c
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 33 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
/examples/terraform.tfstate.backup
/examples/terraform-provider-virtualbox
/examples/ubuntu-15.04.tar.xz
/examples/*
/provider/testdata/
/terraform-provider-virtualbox
.idea/
.idea/
.DS_Store
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# v.0.1.2
- Add support for using external vagrant box and archives as source for deploy

# v.0.1.1.1

- Add support for Terraform v0.9.5

# v0.1.1

- Add new optional field "user_data" in schema, accepts arbitary string, your VM specific configuration can be stored here.
Expand Down
33 changes: 15 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@

Inspired by [terraform-provider-vix](https://github.com/hooklift/terraform-provider-vix)

Fork from [terraform-provider-virtualbox](https://github.com/ccll/terraform-provider-virtualbox) by ccll

# How to install

1. Download prebuilt binaries from [releases](https://github.com/ccll/terraform-provider-virtualbox/releases).
2. Rename downloaded binary file to `terraform-provider-virtualbox`.
3. Copy the `terraform-provider-virtualbox` binary to the same directory as your `terraform` binary.
1. go get github.com/pyToshka/terraform-provider-virtualbox

# How to build from source

1. Make sure you've got [goop](https://github.com/nitrous-io/goop) installed, we are using goop to lock the version of dependencies. `go get -v github.com/nitrous-io/goop`
2. `git clone https://github.com/ccll/terraform-provider-virtualbox.git`
3. Run `goop install` in the cloned repo to install all dependencies.
4. `goop go build` to build this plugin.
5. `goop go install` to install the plugin binary at `.vendor/bin/terraform-provider-virtualbox`. If you are cross-compiling with tools like [gox](https://github.com/mitchellh/gox), run `goop exec gox`, check goop documentation for details.
6. Copy the `terraform-provider-virtualbox` binary to the same directory as your `terraform` binary.
1. git clone https://github.com/pyToshka/terraform-provider-virtualbox
2. cd terraform-provider-virtualbox
3. go get
4. mv terraform-provider-virtualbox example/
5. cd example/
6. terraform plan
7. terraform apply

# Resources

Expand All @@ -26,7 +27,8 @@ Inspired by [terraform-provider-vix](https://github.com/hooklift/terraform-provi
### Schema

- `name`, string, required: The name of the virtual machine.
- `image`, string, required: The url of the image file.
- `image`, string, required: The place of the image file(archive or vagrant box).
- `url`, string, optional, default not set: The url for downloaded vagrant box from external resource (ex. [Ubuntu Vagrant box](https://atlas.hashicorp.com/ubuntu/boxes/trusty64/versions/14.04/providers/virtualbox.box])) . If not set using `image` variable.
- `cpus`, int, optional, default=2: The number of CPUs.
- `memory`, string, optional, default="512mib": The size of memory, allow human friendly units like 'MB', 'MiB'.
- `user_data`, string, optional, default="": User defined data.
Expand Down Expand Up @@ -77,24 +79,19 @@ output "IPAddr" {

# Limitations

- Only local images is allowed, for now.
- Experimental provider!

# Example images

- [ubuntu-15.04](https://github.com/ccll/terraform-provider-virtualbox-images/releases/tag/ubuntu-15.04)

# How to make an image
- [Ubuntu Vagrant box](https://atlas.hashicorp.com/ubuntu/boxes/trusty64/versions/14.04/providers/virtualbox.box])

- An image file is a tarball file in format '.tar.gz', '.tar.bz2' or '.tar.xz'.
- An image tarball should contain atleast one virtual disk files, for now only ".vdi' and '.vmdk' is supported. You can run `VBoxManage clonehd` to convert formats.
- '.vbox' file is ignored as we are creating a brand new VM instead of cloning from existing one, so you can avoid packing them into the image. There might be a small chance your image will not work in the newly created VM if some spec flags varies greatly, but as long as you make your image in a VM created with default flags, things should work smoothly.
- All virtual disk files in the image will be attached to the same SATA controller in **alphabet** order, so name them properly before making the tarball.
- VirtualBox Guest Addition **must** be installed and running in the guest OS, as the IP address is retrieved via it. If you have a better approach which does not require Guest Addition, please write to me, or better, send a PR.

# TODO

- [ ] Optimize resourceVMUpdate(), eliminate unneccessary restarts of VM.
- [ ] Auto download image from remote url.
- [x] Auto download image from remote url.
- [ ] Validate downloaded image against checksum.
- [ ] Download the same image only once (based on checksum).
- [ ] Re-download corrupted image (based on checksum).
Expand Down
28 changes: 18 additions & 10 deletions examples/example.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,32 @@
resource "virtualbox_vm" "node" {
count = 2
name = "${format("node-%02d", count.index+1)}"

image = "./ubuntu-15.04.tar.xz"
url = "https://atlas.hashicorp.com/ubuntu/boxes/trusty64/versions/14.04/providers/virtualbox.box"
image = "./virtualbox-ubuntu.box"
cpus = 2
memory = "512mib"

memory = "512mib",
user_data = "${file("user_data")}"

network_adapter {
type = "nat"
}

network_adapter {
type = "bridged"
host_interface = "en0"
}
}
provisioner "remote-exec" {
inline = [
"touch /tmp/root_setup.sh",
]
connection {
type = "ssh"
user = "vagrant"
password = "vagrant"
}
}

}
output "IPAddr" {
value = "${element(virtualbox_vm.node.*.network_adapter.1.ipv4_address, 1)}"
value = "${element(virtualbox_vm.node.*.network_adapter.0.ipv4_address, 1)}"
}
output "IPAddr_2" {
value = "${element(virtualbox_vm.node.*.network_adapter.0.ipv4_address, 2)}"
}

1 change: 1 addition & 0 deletions provider/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os"
"os/exec"

"path/filepath"
)

Expand Down
65 changes: 61 additions & 4 deletions provider/resource_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import (
"sync"
"time"

vbox "github.com/ccll/go-virtualbox"
vbox "github.com/pyToshka/go-virtualbox"
"github.com/hashicorp/terraform/helper/schema"
multierror "github.com/hashicorp/go-multierror"
"os/exec"
"runtime"
"io"
"net/http"
)
var (
VBM string // Path to VBoxManage utility.
)

func init() {
Expand All @@ -41,6 +48,11 @@ func resourceVM() *schema.Resource {
Required: true,
ForceNew: true,
},
"url": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},

"cpus": &schema.Schema{
Type: schema.TypeInt,
Expand Down Expand Up @@ -124,7 +136,27 @@ var imageOpMutex sync.Mutex

func resourceVMCreate(d *schema.ResourceData, meta interface{}) error {
/* TODO: allow partial updates */

if len(d.Get("url").(string)) > 0 {
path := d.Get("image").(string)
url:= d.Get("url").(string)
// Create the file
out, err := os.Create(path)
if err != nil {
return err
}
defer out.Close()
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Writer the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
}
image := d.Get("image").(string)

/* Get gold folder and machine folder */
Expand Down Expand Up @@ -171,7 +203,14 @@ func resourceVMCreate(d *schema.ResourceData, meta interface{}) error {
/* Clone gold virtual disk files to VM folder */
for _, src := range goldDisks {
filename := filepath.Base(src)

target := filepath.Join(vm.BaseFolder, filename)
VBM = "VBoxManage"
if p := os.Getenv("VBOX_INSTALL_PATH"); p != "" && runtime.GOOS == "windows" {
VBM = filepath.Join(p, "VBoxManage.exe")
}
setuiid := exec.Command(VBM + "internalcommands sethduuid " +src)
err := setuiid.Run()
imageOpMutex.Lock() // Sequentialize image cloning to improve disk performance
err = vbox.CloneHD(src, target)
imageOpMutex.Unlock()
Expand Down Expand Up @@ -370,7 +409,7 @@ func WaitUntilVMIsReady(d *schema.ResourceData, vm *vbox.Machine, meta interface
continue
}
key := fmt.Sprintf("network_adapter.%d.ipv4_address_available", i)
_, err = WaitForVMAttribute(d,[]string{"yes"}, []string{"", "no"}, key, meta, 3*time.Second, 3*time.Second)
_, err = WaitForVMAttribute(d,[]string{"yes"}, []string{"no"}, key, meta, 3*time.Second, 3*time.Second)
if err != nil {
return fmt.Errorf(
"Error waiting for VM (%s) to become ready: %s", d.Get("name"), err)
Expand Down Expand Up @@ -618,6 +657,25 @@ func net_vbox_to_tf(vm *vbox.Machine, d *schema.ResourceData) error {
return nil
}

//func WaitForVMAttribute(d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}, delay, interval time.Duration) (interface{}, error) {
// // Wait for the droplet so we can get the networking attributes
// // that show up after a while
// log.Printf(
// "[INFO] Waiting for VM (%s) to have %s of %s",
// d.Get("name"), attribute, target)
//
// stateConf := &resource.StateChangeConf{
// Pending: pending,
// Target: []string{target},
// Refresh: newVMStateRefreshFunc(d, attribute, meta),
// Timeout: 5 * time.Minute,
// Delay: delay,
// MinTimeout: interval,
// NotFoundChecks: 60,
// }
//
// return stateConf.WaitForState()
//}
func WaitForVMAttribute(
d *schema.ResourceData, target []string, pending []string, attribute string, meta interface{}, delay, interval time.Duration) (interface{}, error) {
// Wait for the droplet so we can get the networking attributes
Expand All @@ -638,7 +696,6 @@ func WaitForVMAttribute(

return stateConf.WaitForState()
}

func newVMStateRefreshFunc(
d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
Expand Down

0 comments on commit 7da910c

Please sign in to comment.