Foreman provider for Terraform (formerly terraform-foreman)
Note, I'm a DevOps Engineer who has come from a predominately Ops world. I have never written in Go previously instead prefering Ruby, Python, Javascript, Java or Bash. Hence this code may actually be completely wrong! Use this at your own risk! If you'd like to contribute please do, see the instructions below!
Terraform is an orchestration tool that can be used to deploy and manage the lifecycle of cloud resources such as virtual machines, DNS records etc. That probably isn't giving it enough credit so check it out at https://terraform.io/
Foreman (or more accurately TheForeman) is a Red Hat sponsored open source tool used to manage infrastructure in a Private Cloud. Foreman can provision for instance Docker instances, Virtual Machines in OpenStack or VMWare and it can even deploy to bare metal. Foreman ties into PuppetLabs Puppet infrastructure and provides ENC data regarding the servers it manages. Check it out at http://theforeman.org/
Install terraform first using the instructions at https://terraform.io/intro/getting-started/install.html
Add the following to your ~/.terraformrc
providers {
foreman = "/path/to/bin/terraform-provider-foreman"
}
Sample terraform config. Save this as a example.tf or similar
provider "foreman" {
username = "myusername"
password = "mypassword"
url = "https://my-foreman.fqdn"
}
resource "foreman_dns" "example" {
host = "example.com"
}
resource "foreman_server" "example" {
name = "host${count.index}.example.com"
location_id = 1
organization_id = 1
puppet_class_ids = ["1","2","3"]
count = 3
}
resource "foreman_server" "complex_VM" {
name = "complex.example.com"
location_id = 1 # ID of foreman location, if locations are enabled
organization_id = 2 # ID of foreman organization, if orgs are enabled
environment_id = 4 # ID of foreman environment
ip = "10.12.2.2"
mac = "00:50:56:8f:29:73"
architecture_id = 1 # x86_64
domain_id = 1 # "First foreman domain"
puppet_proxy_id = 2 # ID of your puppet master defined in foreman
puppet_class_ids = ["351"] # Puppet class ids
operatingsystem_id = 1 # ID of a foreman operating system
medium_id = 7 # ID of a foreman repository
ptable_id = 3 # ID of a foreman partition table
subnet_id = 3 # ID of a foreman subnet
compute_resource_id = 1 # ID of a foreman compute resource, for example vCenter, docker, openstack nova
model_id = 1 # ID of a foreman compute model
owner_id = 17 # ID of a foreman user, likely that of the service account used to create it
puppet_ca_proxy_id = 2 # ID of your puppet CA master defined in foreman
build = false # Build mode, determines if the PXE configs are generated by foreman
enabled = true # Enabled?? NFI
provision_method = "build"
managed = true
comment = ""
}
resource "foreman_server" "myVM" {
name = "hostname"
environment_id = "environment_id"
ip = "10.0.0.2"
mac = "ff:ff:ff:ff:ff:ff"
architecture_id = 1
domain_id = 1
realm_id = 1
puppet_proxy_id = 1
puppetclass_ids = [1,2,3]
operatingsystem_id = 1
medium_id = "1" # yeah, it's a string. idk, don't ask
ptable_id = 1
subnet_id = 1
compute_resource_id = 25
root_pass = "Superawesomehash"
model_id = 1
hostgroup_id = 1
owner_id = 1
owner_type = "User" # must be either User or Usergroup
puppet_ca_proxy_id = 1
image_id = 1
build = true
enabled = true
provision_method = "build"
managed = true
progress_report_id = "progress_report_id"
comment = "Build purpose"
capabilities = "Something"
compute_profile_id = 1
host_parameters_attributes {
roles = "server_role"
puppet = "true"
chef = "false"
}
interfaces_attributes{
mac = "ff:ff:ff:ff:ff:ff"
ip = "ip"
name = "name"
subnet_id = 1
domain_id = 1
identifier = "identifier"
managed = true
primary = true
provision = true
username = "username" # only for bmc
password = "password" # only for bmc
provider = "provider" # only accepted IPMI
virtual = false
tag = "tag"
attached_to = "something"
mode = "mode" # with validations
attached_devices = []string
bond_options = "bond opts"
}
compute_attributes {
cpus = "2"
start = "1"
cluster = "clustername"
memory_mb = "2048"
guest_id = "guest_id"
}
volumes_attributes{
name = "name"
size_gb = 16
_delete = "false"
datastore "Datastore_name"
}
}
if you have already built the terraform-foreman source then you are ready to test. Navigate to the directory where you saved your terraform config (example.tf) and execute:
terraform plan
This will interrogate the provider and should output something similar to TODO
if you have already planned the terraform resources you can taint them essentially marking them to be rebuilt
# Taint the complex example vm
terraform taint foreman_server.complex_VM
Now you can write your own plan similar to the example. Reference the terraform documentation at https://terraform.io/intro/getting-started/build.html
Once a plan has been created you are ready to apply the plan and actually deploy.
Currently I havent implemented the API calls directly to foreman, instead I have utilized foreman's Hammer CLI. I fully intend to replace this at some stage. It is simply a means to an end at this stage. Also only create has been completed, ran out of time this week. Follow the instructions on the Hammer guthub page for installation
# In the directory of your my_custom_terraform.tf file
terraform apply
This will interrogate the provider and make the changes. If a server isn't built for instance it will call the create method and the provider will instantiate the resource.
In order to build/install the source, navigate to the checked out directory and ensure your $GOPATH is defined.
Execute
go install
If you'd like to contribute to this codebase please do!
I would be more than pleased if you did but please remember I am not a programmer by default. Go easy on me! lol
# Fork it on GitHub
git clone https://github.com/your_name/terraform-provider-foreman.git
cd terraform-provider-foreman
git checkout -b my_awesome_feature_branch master
# Make your awesome changes
git commit -a -m "my awesome changes explained"
# Repeat till your happy
git push origin my_awesome_feature_branch
# Submit a pull request at https://github.com/your_name/terraform-provider-foreman
# Explain your changes in PR and include test instrcutions.
# I'll hopefully accept it and we'll be on our way to shared awesomeness.