3

I am looking into setting up VM infrastructure using Terraform and initiatize the VM using cloud-init. I am trying multipart approach using cloud-config content type for the first part, shellscript for the second part.

However, upon terraform apply, only the first part get executed, whereas the second part did not run (by checking the resulting VM whether the changes had been applied).

The relevant configuration part is as below.

data "template_cloudinit_config" "config" {
  gzip = true
  base64_encode = true
  part {
      filename = "init-cloud-config"
      content_type = "text/cloud-config"
      content = file("../modules/services/${var.service_name}/init.yaml")
  }
  part {
      filename = "init-shellscript"
      content_type = "text/x-shellscript"
      content = templatefile("../modules/services/${var.service_name}/init.sh",
        { hostname = "${var.prefix}-${var.service_name}" }
      )
  }
}

Content of cloud-init init.yaml as below

groups:
  - dataops

users:
  - default
  - name: dataops
    gecos: Data Operations
    shell: /bin/bash
    primary_group: dataops
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, admin
    lock_passwd: false

package_update: true

packages:
  - wget

Content of shellscript init.sh is just one line

hostnamectl set-hostname testconfig

Error from cloud-init.log as below

2021-06-29 16:09:51,315 - util.py[DEBUG]: Running command ['/var/lib/cloud/instance/scripts/init-shellscript'] with allowed return codes [0] (shell=False, capture=False)
2021-06-29 16:09:51,317 - util.py[WARNING]: Failed running /var/lib/cloud/instance/scripts/init-shellscript [-]
2021-06-29 16:09:51,317 - util.py[DEBUG]: Failed running /var/lib/cloud/instance/scripts/init-shellscript [-]
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/cloudinit/util.py", line 2048, in subp
    env=env, shell=shell)
  File "/usr/lib64/python3.6/subprocess.py", line 729, in __init__
    restore_signals, start_new_session)
  File "/usr/lib64/python3.6/subprocess.py", line 1364, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: b'/var/lib/cloud/instance/scripts/init-shellscript'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/cloudinit/util.py", line 896, in runparts
    subp(prefix + [exe_path], capture=False)
  File "/usr/lib/python3.6/site-packages/cloudinit/util.py", line 2056, in subp
    stderr="-" if decode else b"-")
cloudinit.util.ProcessExecutionError: Exec format error. Missing #! in script?
Command: ['/var/lib/cloud/instance/scripts/init-shellscript']
Exit code: -
Reason: [Errno 8] Exec format error: b'/var/lib/cloud/instance/scripts/init-shellscript'
Stdout: -
Stderr: -
2021-06-29 16:09:51,329 - cc_scripts_user.py[WARNING]: Failed to run module scripts-user (scripts in /var/lib/cloud/instance/scripts)
2021-06-29 16:09:51,330 - handlers.py[DEBUG]: finish: modules-final/config-scripts-user: FAIL: running config-scripts-user with frequency once-per-instance
2021-06-29 16:09:51,330 - util.py[WARNING]: Running module scripts-user (<module 'cloudinit.config.cc_scripts_user' from '/usr/lib/python3.6/site-packages/cloudinit/config/cc_scripts_user.py'>) failed    
2021-06-29 16:09:51,330 - util.py[DEBUG]: Running module scripts-user (<module 'cloudinit.config.cc_scripts_user' from '/usr/lib/python3.6/site-packages/cloudinit/config/cc_scripts_user.py'>) failed      
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/cloudinit/stages.py", line 852, in _run_modules
    freq=freq)
  File "/usr/lib/python3.6/site-packages/cloudinit/cloud.py", line 54, in run
    return self._runners.run(name, functor, args, freq, clear_on_fail)
  File "/usr/lib/python3.6/site-packages/cloudinit/helpers.py", line 187, in run
    results = functor(*args)
  File "/usr/lib/python3.6/site-packages/cloudinit/config/cc_scripts_user.py", line 45, in handle
    util.runparts(runparts_path)
  File "/usr/lib/python3.6/site-packages/cloudinit/util.py", line 903, in runparts
    % (len(failed), len(attempted)))
RuntimeError: Runparts: 1 failures in 1 attempted commands
2021-06-29 16:09:51,356 - stages.py[DEBUG]: Running module ssh-authkey-fingerprints (<module 'cloudinit.config.cc_ssh_authkey_fingerprints' from '/usr/lib/python3.6/site-packages/cloudinit/config/cc_ssh_authkey_fingerprints.py'>) with frequency once-per-instance
zaidwaqi
  • 609
  • 1
  • 8
  • 25
  • Where is the user data being ran? eg AWS/GCP/somewhere else? Does all of the user data parts end up on the machine? What does `/var/log/cloud-init.log` and `/var/log/cloud-init-output.log` show? Can you share your user data parts? – ydaetskcoR Jun 29 '21 at 15:13
  • For reference, the `template_file` data source has been deprecated in favour of the `templatefile` function that you're already using slightly confusingly. You can use it in line with `content = templatefile("../modules/services/${var.service_name}/init.sh", { hostname = "${var.prefix}-${var.service_name}" }`. And for the first one it doesn't look like a template at all so you can just use `content = file("../modules/services/${var.service_name}/init.yaml")`. – ydaetskcoR Jun 29 '21 at 15:15
  • thanks for simplified approach. edited as advised – zaidwaqi Jun 29 '21 at 16:20

1 Answers1

5

The relevant line in that error is this:

cloudinit.util.ProcessExecutionError: Exec format error. Missing #! in script?

For cloud-init to run a user-data shell script it needs to know what the interpreter is going to be so must begin with a shebang - #! - and the path to the interpreter so your script should instead look like this:

#!/bin/sh
hostnamectl set-hostname testconfig

Or in your case it's a template expecting the hostname to be passed in as a variable so it should be:

#!/bin/sh
hostnamectl set-hostname ${hostname}
ydaetskcoR
  • 53,225
  • 8
  • 158
  • 177