Skip to content

Commit 2e2fe78

Browse files
authored
Remove build flag and re-introduce provision method attribute (#122)
* Remove build flag and re-introduce provision method attribute The build flag was introduced as the replacement for the "method" attribute. Earlier, the method could be set to "build" or "image", which is then used by Foreman. The initial creation of a host also needed the build flag to be set in the API request to signal Foreman that it should create the machine. This lead to the problem that Terraform configs containing "build = true" would reset the build flag in Foreman even for existing, already built machines, resetting them at the next boot. This is dangerous and should be avoided. The commit removes the build flag completely from Terraform and uses the "provision_method" attribute from the Foreman API (again). We will have to find an additional attribute to support the use case of "enforced rebuild" that originally lead to the switch. The "managed" flag is not changed. Refs #40 Refs #68 Refs #106 * Add checks for image_id in compute_attributes in image-based provisioning See examples/host/vmware_imagebased_host.tf for a VMware-backed image VM Refs #103 Refs #102 Refs #105 * Fix test with failing provision_method Mock attribute * Remove VMware-specific checks in ProvisionMethod==image in host creation Removes an experimental check of the compute_attributes when using "image"-based host creation. The backend providers need different values. VMware for example needs the image_id as UUID, see the example file in examples/host/vmware_imagebased_host.tf Refs #125
1 parent bea2504 commit 2e2fe78

File tree

4 files changed

+78
-30
lines changed

4 files changed

+78
-30
lines changed
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
data "foreman_image" "ubuntu" {
2+
name ="ubuntu-22.04"
3+
compute_resource_id = data.foreman_computeresource.my_vmware_cluster.id
4+
}
5+
6+
7+
resource "foreman_host" "image_based_machine" {
8+
count = var.hosts.count
9+
name = format("my-image-based-machine-%d", count.index + 1)
10+
provision_method = "image"
11+
12+
# This is the Foreman-internal image ID, integer
13+
# TODO: Do we need two image IDs, int and UUID?
14+
image_id = data.foreman_image.ubuntu.id
15+
16+
# The image_id JSON attribute is required in image-based setups on VMware! It must contain the VMware-internal UUID
17+
compute_attributes = format(<<EOF
18+
{
19+
"image_id": "%s"
20+
}
21+
EOF
22+
, data.foreman_image.ubuntu.uuid)
23+
24+
hostgroup_id = foreman_hostgroup.ubuntu.id
25+
compute_resource_id = data.foreman_computeresource.my_vmware_cluster.id
26+
}
27+
28+
29+
resource "foreman_hostgroup" "ubuntu" {
30+
name = var.group
31+
32+
# Not complete, fill with your own data
33+
}

foreman/api/host.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,13 @@ type ForemanHost struct {
5050

5151
// Whether or not to rebuild the host on reboot
5252
Build bool `json:"build"`
53+
// Current build status
54+
// From Foreman: BUILT = 0, PENDING = 1, TOKEN_EXPIRED = 2, BUILD_FAILED = 3
55+
BuildStatus int `json:"build_status"`
56+
// Current build status label
57+
BuildStatusLabel string `json:"build_status_label"`
5358
// Describes the way this host will be provisioned by Foreman
54-
Method string `json:"provision_method,omitempty"`
59+
ProvisionMethod string `json:"provision_method,omitempty"`
5560
// ID of the domain to assign the host
5661
DomainId *int `json:"domain_id,omitempty"`
5762
// Name of the Domain. To substract from the Machine name
@@ -101,6 +106,10 @@ type ForemanHost struct {
101106
PuppetAttributes PuppetAttribute `json:"puppet_attributes"`
102107
}
103108

109+
func (fh *ForemanHost) isBuilt() bool {
110+
return fh.BuildStatus == 0
111+
}
112+
104113
// ForemanInterfacesAttribute representing a hosts defined network interfaces
105114
type ForemanInterfacesAttribute struct {
106115
Id int `json:"id,omitempty"`

foreman/resource_foreman_host.go

+33-29
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ func resourceForemanHostV0() *schema.Resource {
8383
"Note: Changes to this attribute will trigger a host rebuild.",
8484
),
8585
},
86+
8687
"parameters": {
8788
Type: schema.TypeMap,
8889
ForceNew: false,
@@ -342,17 +343,16 @@ func resourceForemanHost() *schema.Resource {
342343
},
343344
},
344345

345-
// -- Optional --
346-
347-
"method": {
348-
Type: schema.TypeString,
349-
Optional: true,
350-
Deprecated: "The argument is handled by build instead",
346+
"provision_method": {
347+
Type: schema.TypeString,
348+
ForceNew: true,
349+
Optional: true,
350+
Default: "build",
351351
ValidateFunc: validation.StringInSlice([]string{
352-
"build",
353-
"image",
352+
"build", // build = Network Based
353+
"image", // image = Image Based
354354
}, false),
355-
Description: "REMOVED - use build argument instead to manage build flag of host.",
355+
Description: "Sets the provision method in Foreman for this host: either network-based ('build') or image-based ('image')",
356356
},
357357

358358
"comment": {
@@ -365,6 +365,7 @@ func resourceForemanHost() *schema.Resource {
365365
"Note: Changes to this attribute will trigger a host rebuild.",
366366
),
367367
},
368+
368369
"parameters": {
369370
Type: schema.TypeMap,
370371
ForceNew: false,
@@ -386,34 +387,21 @@ func resourceForemanHost() *schema.Resource {
386387
"boot to PXE and power on. Defaults to `false`.",
387388
},
388389

389-
"manage_build": {
390-
Type: schema.TypeBool,
391-
Optional: true,
392-
Deprecated: "The feature was merged into the new key managed",
393-
Description: "REMOVED, please use the new 'managed' key instead." +
394-
" Create host only, don't set build status or manage power states",
395-
},
396-
397390
"managed": {
398391
Type: schema.TypeBool,
399392
Optional: true,
400393
Default: true,
401394
Description: "Whether or not this host is managed by Foreman." +
402395
" Create host only, don't set build status or manage power states.",
403396
},
404-
"build": {
405-
Type: schema.TypeBool,
406-
Optional: true,
407-
Default: true,
408-
Description: "Whether or not this host's build flag will be enabled in Foreman. Default is true, " +
409-
"which means host will be built at next boot.",
410-
},
397+
411398
"manage_power_operations": {
412399
Type: schema.TypeBool,
413400
Optional: true,
414401
Default: true,
415402
Description: "Manage power operations, e.g. power on, if host's build flag will be enabled.",
416403
},
404+
417405
"retry_count": {
418406
Type: schema.TypeInt,
419407
Optional: true,
@@ -732,8 +720,9 @@ func buildForemanHost(d *schema.ResourceData) *api.ForemanHost {
732720
host.Comment = d.Get("comment").(string)
733721
host.OwnerType = d.Get("owner_type").(string)
734722
host.DomainName = d.Get("domain_name").(string)
723+
724+
host.ProvisionMethod = d.Get("provision_method").(string)
735725
host.Managed = d.Get("managed").(bool)
736-
host.Build = d.Get("build").(bool)
737726
host.Token = d.Get("token").(string)
738727

739728
ownerId := d.Get("owner_id").(int)
@@ -760,10 +749,14 @@ func buildForemanHost(d *schema.ResourceData) *api.ForemanHost {
760749
if mediumId != 0 {
761750
host.MediumId = &mediumId
762751
}
752+
753+
// TODO: How is this parameter used?
754+
// VMware-backed providers need the UUID instead of the Foreman-internal ID
763755
imageId := d.Get("image_id").(int)
764756
if imageId != 0 {
765757
host.ImageId = &imageId
766758
}
759+
767760
modelId := d.Get("model_id").(int)
768761
if modelId != 0 {
769762
host.ModelId = &modelId
@@ -953,6 +946,10 @@ func setResourceDataFromForemanHost(d *schema.ResourceData, fh *api.ForemanHost)
953946
log.Printf("[WARN] error setting compute attributes: %s", err)
954947
}
955948

949+
// See issue #115 for "Build" attribute
950+
d.Set("managed", fh.Managed)
951+
d.Set("provision_method", fh.ProvisionMethod)
952+
956953
d.Set("domain_id", fh.DomainId)
957954
d.Set("domain_name", fh.DomainName)
958955
d.Set("environment_id", fh.EnvironmentId)
@@ -1046,11 +1043,19 @@ func resourceForemanHostCreate(ctx context.Context, d *schema.ResourceData, meta
10461043
client := meta.(*api.Client)
10471044
h := buildForemanHost(d)
10481045

1049-
managed := d.Get("managed").(bool)
1046+
// NOTE(ALL): Set the build flag to true on host create
1047+
if h.ProvisionMethod == "build" && h.Managed {
1048+
h.Build = true
1049+
}
10501050

10511051
log.Debugf("ForemanHost: [%+v]", h)
10521052
hostRetryCount := d.Get("retry_count").(int)
10531053

1054+
// See commit ad2b5890f09645513b520f12291546f26b812c96 for an experimental implementation
1055+
// for checks of the "computeAttributes" field, when using ProvisionMethod=image.
1056+
// The feature was removed because it was VMware-specific and the test on the backend provider
1057+
// could not yet be implemented (via client.ReadComputeResource -> computeResource.Provider)
1058+
10541059
createdHost, createErr := client.CreateHost(ctx, h, hostRetryCount)
10551060
if createErr != nil {
10561061
return diag.FromErr(createErr)
@@ -1065,15 +1070,14 @@ func resourceForemanHostCreate(ctx context.Context, d *schema.ResourceData, meta
10651070

10661071
setResourceDataFromForemanHost(d, createdHost)
10671072

1068-
enablebmc := d.Get("enable_bmc").(bool)
10691073
ManagePowerOperations := d.Get("manage_power_operations").(bool)
10701074

10711075
// Manage power operations only if needed, default is true
10721076
if ManagePowerOperations {
10731077
var powerCmds []interface{}
10741078
// If enable_bmc is true, perform required power off, pxe boot and power on BMC functions
10751079
// Don't modify power state at all if we're not managing the build
1076-
if enablebmc {
1080+
if h.EnableBMC {
10771081
log.Debugf("Calling BMC Reboot/PXE Functions")
10781082
// List of BMC Actions to perform
10791083
powerCmds = []interface{}{
@@ -1084,7 +1088,7 @@ func resourceForemanHostCreate(ctx context.Context, d *schema.ResourceData, meta
10841088
PowerAction: api.PowerCycle,
10851089
},
10861090
}
1087-
} else if managed {
1091+
} else if h.Managed {
10881092
log.Debugf("Using default Foreman behaviour for startup")
10891093
powerCmds = []interface{}{
10901094
api.Power{

foreman/resource_foreman_host_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func ForemanHostToInstanceState(obj api.ForemanHost) *terraform.InstanceState {
3737
}
3838
attr["domain_name"] = obj.DomainName
3939
attr["build"] = strconv.FormatBool(obj.Build)
40+
attr["provision_method"] = obj.ProvisionMethod
41+
4042
if obj.EnvironmentId != nil {
4143
attr["environment_id"] = strconv.Itoa(*obj.EnvironmentId)
4244
}

0 commit comments

Comments
 (0)