Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

atomic_helper.py: ensure presence of parent directories #4938

Merged
merged 1 commit into from
Mar 11, 2024

Conversation

sshedi
Copy link
Contributor

@sshedi sshedi commented Feb 22, 2024

Proposed Commit Message

fix(atomic_helper.py): ensure presence of parent directories

Additional Context

Test Steps

Steps to reproduce:

$ cloud-init clean -ls
$ cloud-init -d modules -m init
2024-02-22 18:59:46,522 - handlers.py[DEBUG]: start: modules-init: running modules for init
2024-02-22 18:59:46,522 - util.py[DEBUG]: Reading from /proc/uptime (quiet=False)
....
[('set_hostname', FileNotFoundError(2, 'No such file or directory'))]

Checklist

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

Copy link
Contributor

@aciba90 aciba90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cloud-init modules is expected to run after cloud-init init --local and cloud-init init and be driven by init-system services.

The config modules corresponding to the init phase, cloud-init modules -m init, are run as part of cloud-init init.

Not sure if we want to support this path in general, if yes, I have some concerns as:

  1. What's the performance impact of this change.
  2. What about the permissions of created parent directories?
  3. Is this the correct place to do this, or would be better to ensure that necessary parent directories are pre-created upper in the call stack? or should we control the creation of the parent dir with a parameter in this function.

That said, why not just run cloud-init init --local, which will create the paths you are missing, before executing cloud-init modules -m init.

@holmanb
Copy link
Member

holmanb commented Feb 23, 2024

@sshedi what is the absolute file path for the missing file? and how are you hitting this?

@aciba90 aciba90 removed their assignment Feb 23, 2024
@sshedi
Copy link
Contributor Author

sshedi commented Feb 23, 2024

@sshedi what is the absolute file path for the missing file? and how are you hitting this?

2024-02-23 18:18:43,099 - util.py[WARNING]: Running module set_hostname (<module 'cloudinit.config.cc_set_hostname' from '/usr/lib/python3.10/site-packages/cloudinit/config/cc_set_hostname.py'>) failed
2024-02-23 18:18:43,099 - util.py[DEBUG]: Running module set_hostname (<module 'cloudinit.config.cc_set_hostname' from '/usr/lib/python3.10/site-packages/cloudinit/config/cc_set_hostname.py'>) failed
Traceback (most recent call last):
  File "/usr/lib/python3.10/site-packages/cloudinit/config/modules.py", line 255, in _run_modules
    ran, _r = cc.run(
  File "/usr/lib/python3.10/site-packages/cloudinit/cloud.py", line 60, in run
    return self._runners.run(name, functor, args, freq, clear_on_fail)
  File "/usr/lib/python3.10/site-packages/cloudinit/helpers.py", line 172, in run
    results = functor(**args)
  File "/usr/lib/python3.10/site-packages/cloudinit/config/cc_set_hostname.py", line 135, in handle
    write_json(prev_fn, {"hostname": hostname, "fqdn": fqdn})
  File "/usr/lib/python3.10/site-packages/cloudinit/atomic_helper.py", line 89, in write_json
    return write_file(
  File "/usr/lib/python3.10/site-packages/cloudinit/atomic_helper.py", line 65, in write_file
    raise e
  File "/usr/lib/python3.10/site-packages/cloudinit/atomic_helper.py", line 46, in write_file
    tf = tempfile.NamedTemporaryFile(
  File "/usr/lib/python3.10/tempfile.py", line 559, in NamedTemporaryFile
    file = _io.open(dir, mode, buffering=buffering,
  File "/usr/lib/python3.10/tempfile.py", line 556, in opener
    fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
  File "/usr/lib/python3.10/tempfile.py", line 256, in _mkstemp_inner
    fd = _os.open(file, flags, 0o600)
FileNotFoundError: [Errno 2] No such file or directory: '/var/lib/cloud/data/tmplmv88658'

Above is the full traceback of the error.

@sshedi
Copy link
Contributor Author

sshedi commented Feb 23, 2024

Thanks for the inputs and clarifications. Please find my replies inline.

cloud-init modules is expected to run after cloud-init init --local and cloud-init init and be driven by init-system services.

[sshedi]: In that case, cloud-init init should not be allowed to run before running cloud-init --local and it should be validated, right? Please correct me if my understanding is wrong.

The config modules corresponding to the init phase, cloud-init modules -m init, are run as part of cloud-init init.

Not sure if we want to support this path in general, if yes, I have some concerns as:

[sshedi]: Even if it's not supported, this should not end in a traceback. There is possibility of a use case where someone might use cloud-init for setting hostname only and nothing else.

1. What's the performance impact of this change.

[sshedi]: should not be much, if it's done in the order you mentioned, this directory gets created when local stage is run but now this is happening here.

2. What about the permissions of created parent directories?

[sshedi]: this is creating the missing data dir under /var/lib/cloud/ and with and without this change, the permissions are 755.

3. Is this the correct place to do this, or would be better to ensure that necessary parent directories are pre-created upper in the call stack? or should we control the creation of the parent dir with a parameter in this function.

[sshedi]: Adding a parameter to this function might be an overkill, enure_dir will create the dir only if the dir doesn't exist.
My question here is, should we use ensure_dirs instead.

That said, why not just run cloud-init init --local, which will create the paths you are missing, before executing cloud-init modules -m init.
[sshedi]: Like I mentioned above, it's a debatable topic. Running --local sounds reasonable but it'll be good if set_hostname without a traceback.

@sshedi sshedi force-pushed the write-file branch 2 times, most recently from c71049b to ef12d0b Compare March 2, 2024 04:46
@aciba90 aciba90 self-assigned this Mar 4, 2024
Copy link
Contributor

@aciba90 aciba90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @sshedi!

cloud-init modules is expected to run after cloud-init init --local and cloud-init init and be driven by init-system services.

[sshedi]: In that case, cloud-init init should not be allowed to run before running cloud-init --local and it should be validated, right? Please correct me if my understanding is wrong.

A normal execution path is:

  1. cloud-init init --local
  2. cloud-init init
  3. cloud-init modules --mode config
  4. cloud-init modules --mode final

in that order, and the init config modules are executed as part of cloud-init init. cloud-init modules --mode init is a command mostly for debugging purposes that we are going to deprecate to avoid confusion.

See boot-stages for more info.

[sshedi]: Even if it's not supported, this should not end in a traceback. There is possibility of a use case where someone might use cloud-init for setting hostname only and nothing else.

I agree, we shouldn't end up with a traceback. Maybe cloud-init single --name set_hostname --frequency always is more appropiate to your use case, if you only want to set the hostname, see single. But, if cloud-init init --local / cloud-init init did not run, some ds meta-data / cloud-config could be not yet fetched.

  1. What about the permissions of created parent directories?

[sshedi]: this is creating the missing data dir under /var/lib/cloud/ and with and without this change, the permissions are 755.

The concern was about other code paths creating folders on other locations with opener permissions, I have double-checked that the main folders that cloud-init interacts are all with 755 root:root, so we are safe with util.ensure_dir.

# tree -pdug /etc/cloud/ /var/run/cloud-init/ /var/lib/cloud/
[drwxr-xr-x root     root    ]  /etc/cloud/
├── [drwxr-xr-x root     root    ]  clean.d
├── [drwxr-xr-x root     root    ]  cloud.cfg.d
└── [drwxr-xr-x root     root    ]  templates
[drwxr-xr-x root     root    ]  /var/run/cloud-init/
└── [drwxr-xr-x root     root    ]  sem
[drwxr-xr-x root     root    ]  /var/lib/cloud/
├── [drwxr-xr-x root     root    ]  data
├── [drwxr-xr-x root     root    ]  handlers
├── [lrwxrwxrwx root     root    ]  instance -> /var/lib/cloud/instances/5b18e235-17ad-41b5-a5b7-44569c20bdf3
├── [drwxr-xr-x root     root    ]  instances
│   └── [drwxr-xr-x root     root    ]  5b18e235-17ad-41b5-a5b7-44569c20bdf3
│       ├── [drwxr-xr-x root     root    ]  handlers
│       ├── [drwxr-xr-x root     root    ]  scripts
│       └── [drwxr-xr-x root     root    ]  sem
├── [drwxr-xr-x root     root    ]  scripts
│   ├── [drwxr-xr-x root     root    ]  per-boot
│   ├── [drwxr-xr-x root     root    ]  per-instance
│   ├── [drwxr-xr-x root     root    ]  per-once
│   └── [drwxr-xr-x root     root    ]  vendor
├── [drwxr-xr-x root     root    ]  seed
└── [drwxr-xr-x root     root    ]  sem

[sshedi]: Adding a parameter to this function might be an overkill, enure_dir will create the dir only if the dir doesn't exist.
My question here is, should we use ensure_dirs instead.

Yeah, I think util.ensure_dir is more appropriate as we know we are going to create only one directory.

cloudinit/atomic_helper.py Outdated Show resolved Hide resolved
Signed-off-by: Shreenidhi Shedi <shreenidhi.shedi@broadcom.com>
Copy link
Contributor

@aciba90 aciba90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks @sshedi!

@aciba90 aciba90 merged commit ccd438e into canonical:main Mar 11, 2024
29 checks passed
@sshedi
Copy link
Contributor Author

sshedi commented Mar 12, 2024

Thanks for taking the fix 🙏 Have a nice time ahead.

@sshedi sshedi deleted the write-file branch May 1, 2024 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants