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

Move disable checks out of systemd generator #4399

Merged
merged 7 commits into from
Oct 9, 2023

Conversation

holmanb
Copy link
Member

@holmanb holmanb commented Aug 30, 2023

Please do not squash merge this PR.

The commits in this PR are written separately with the intent of being added to the git tree individually.

Old squashed commit message
Move disable checks out of systemd generator

- Add environment variable check to unit conditionals
- Change unit conditionals from rhel-only to all distros
- Add unit conditionals to cloud-init target
- Makefile: Benchmark generator script
- generator: Remove redundant code
- generator: Eliminate variables, branches and functions
- docs: Describe environment variable disablement method
- cloud-init status: Fix bug in containers where
  disabling cloud-init with KERNEL_CMDLINE causes
  cloud-init status --wait to loop indefinitely
- Add integration test coverage for disablement


- KERNEL_CMDLINE environment variable is now checked on
  all platforms which may simplify testing and presents
  minimal risk of unintended use.
- Kernel cmdline, cloud-init.disabled, and KERNEL_CMDLINE
  environment variable now have higher precedence than
  ds-identify policy in all distros, not just RHEL. 

https://www.freedesktop.org/software/systemd/man/systemd.unit.html
https://www.freedesktop.org/software/systemd/man/systemd-analyze.html

Behavior changes:

Additional Details

Motivations: eliminate redundant code, performance improvements (do less in systemd generator, which blocks all of boot), standardize behavior across distros

The current cloud-init docs that describe how to disable cloud-init are incomplete, since ds-identify policy may take precedence over the disable file, the kernel commandline and environment variable arguments. This is not ideal, as ds-identify.cfg is an undocumented and less user-friendly user interface for a common user operation.

Assuming that we want cloud-init to behave as the docs describe (i.e.: touch /etc/cloud/cloud-init.disabled actually disables cloud-init), this PR fixes that discrepancy between docs and behavior.

Performance Implications

As @blackboxsw mentioned out of band:

having the disable in generator script timeframe may solve the case earlier than having systemd's ordering logic have to calculate and redact the cloud-init* boot stages from boot. Not sure if that matters in terms of boot time.

and some of my own thoughts:

The current generator code may allow the systemd ordering solver to run sooner without cloud-init, but it also delays all of boot with checking kernel commandline and cloud-init.disabled file while the generator is running (in a shell script), so I think there are perf costs and benefits with this (potential) change.

Where the benefit of the generator pruning out cloud-init only improves performance in the case that cloud-init isn't running (by skipping ds-identify), and the potential speed benefit is the case where cloud-init is not disabled (by eliminating a redundant systemd-detect-virt call, and kernel cmdline and file checking that could be done by systemd later, and potentially faster).

Benchmarking the systemd generator shows a 2-3x performance improvement. However, this appears negligible since systemd-analyze critical-chain shows identical times for both (below) - and some work does get shifted from the generator to systemd itself in this change (later in boot).

Generator Benchmark: this branch

# make benchmark-generator 
python3 ./tools/render-cloudcfg --variant="benchmark" ./systemd/cloud-init-generator.tmpl ./systemd/cloud-init-generator
./tools/benchmark.sh ./systemd/cloud-init-generator

real	0m0.210s
user	0m0.140s
sys	0m0.072s
root@cloudinit-0901-025531ijbm4hwd:~/cloud-init# make benchmark-generator 
python3 ./tools/render-cloudcfg --variant="benchmark" ./systemd/cloud-init-generator.tmpl ./systemd/cloud-init-generator
./tools/benchmark.sh ./systemd/cloud-init-generator

real	0m0.225s
user	0m0.162s
sys	0m0.068s

Generator Benchmark: tip of main with just benchmark commit applied (6cf53172a)

# make benchmark-generator 
python3 ./tools/render-cloudcfg --variant="benchmark" ./systemd/cloud-init-generator.tmpl ./systemd/cloud-init-generator
./tools/benchmark.sh ./systemd/cloud-init-generator

real	0m0.631s
user	0m0.361s
sys	0m0.268s
root@cloudinit-0901-025531ijbm4hwd:~/cloud-init# make benchmark-generator 
python3 ./tools/render-cloudcfg --variant="benchmark" ./systemd/cloud-init-generator.tmpl ./systemd/cloud-init-generator
./tools/benchmark.sh ./systemd/cloud-init-generator

real	0m0.710s
user	0m0.353s
sys	0m0.360s

systemd-analyze critical chain

note: I think that the time is since systemd starts, but if a better methodology exists, feedback is welcome

with this change:

root@cloudinit-0901-025531ijbm4hwd:~# systemd-analyze critical-chain cloud-init-local.service
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

cloud-init-local.service +749ms
└─systemd-remount-fs.service @185ms +6ms
  └─systemd-journald.socket @176ms
    └─-.mount @147ms
      └─-.slice @147ms

from tip of main:

root@cloudinit-0901-025531ijbm4hwd:~# systemd-analyze critical-chain cloud-init-local.service 
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

cloud-init-local.service +749ms
└─systemd-remount-fs.service @185ms +6ms
  └─systemd-journald.socket @176ms
    └─-.mount @147ms
      └─-.slice @147ms

Since the root slice starts at 147ms for both tip of main and this branch, this change doesn't appear to provide a performance regression.

Measuring with and without conditionals in .target

From a different (slower) machine (don't compare the times below with the times above), I compare this branch:

# systemd-analyze critical-chain cloud-init-local.service
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

cloud-init-local.service +884ms
└─systemd-journald.socket @299ms
  └─-.mount @219ms
    └─system.slice @219ms
      └─-.slice @219ms

against an otherwise identical branch that drops f310f9a:

# systemd-analyze critical-chain cloud-init-local.service
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

cloud-init-local.service +1.098s
└─systemd-journald.socket @316ms
  └─-.mount @243ms
    └─system.slice @242ms
      └─-.slice @243ms

I'd be surprised if this conditional to the target is actually an optimization that would save 0.2 seconds, so I assume that the measurable difference due to the target conditional is within the noise - not something to be concerned about.

Test Steps

Systemd environment conditional test:

arc~ systemd-analyze condition 'ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled' 
test.service: ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled succeeded.
Conditions succeeded.
arc~ export KERNEL_CMDLINE=cloud-init=disabled                                           
arc~ systemd-analyze condition 'ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled'
test.service: ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled failed.
Conditions failed.

Integration Tests:

tox -e integration-tests -- tests/integration_tests/test_kernel_commandline_match.py

@holmanb
Copy link
Member Author

holmanb commented Sep 1, 2023

@smoser @raharper @ani-sinha @esposem Given the invasive nature this change, I am requesting feedback from you directly on this pull request.

A few specific things I'd like to draw attention to:

  1. With this change, cloud-init now prioritizes the currently documented methods of disabling cloud-init over the ds-identify policy in all distros (formerly just RHEL) via systemd's conditional unit execution - is this acceptable behavior change? This should allow existing ds-identify policy to still work, but be overridden in the case that a user disables cloud-init as described in the docs. Are there any use cases that would be broken by this?
  2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.
  3. The new environment variable conditional ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled.
  4. The changes in cloud-init-generator.tmpl

@ani-sinha
Copy link
Contributor

@smoser @raharper @ani-sinha @esposem Given the invasive nature this change, I am requesting feedback from you directly on this pull request.

A few specific things I'd like to draw attention to:

  1. With this change, cloud-init now prioritizes the currently documented methods of disabling cloud-init over the ds-identify policy in all distros (formerly just RHEL) via systemd's conditional unit execution - is this acceptable behavior change? This should allow existing ds-identify policy to still work, but be overridden in the case that a user disables cloud-init as described in the docs. Are there any use cases that would be broken by this?
  2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.

This needs to be tested. We are going to test this internally.

  1. The new environment variable conditional ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled.
  2. The changes in cloud-init-generator.tmpl

@raharper
Copy link
Collaborator

raharper commented Sep 1, 2023

@smoser @raharper @ani-sinha @esposem Given the invasive nature this change, I am requesting feedback from you directly on this pull request.

A few specific things I'd like to draw attention to:

1. With this change, cloud-init now prioritizes the [currently
documented methods of disabling
cloud-init](https://cloudinit.readthedocs.io/en/latest/howto/disable_cloud_init.html)
over the ds-identify policy in all distros (formerly just RHEL) via
systemd's conditional unit execution - is this acceptable behavior

Thanks for looking into this; it was certainly non-obvious why adding
documented parameters didn't appear to disable cloud-init in some scenarios.

In the open issue w.r.t Azure+Packer -- I think we've come to the conclusion
(though yet to be verified) that something external to cloud-init is the
cause of additional invocations of cloud-init, rather than that the documented
method does not work.

The documentation works AFAICT in the absence of that packer scenario:

Using the touch method, for example:

# ls -al /etc/cloud/cloud-init.disabled
-rw-r--r-- 1 root root 0 Sep  1 18:47 /etc/cloud/cloud-init.disabled

# systemctl status cloud-init.target
○ cloud-init.target - Cloud-init target
     Loaded: loaded (/lib/systemd/system/cloud-init.target; static)
     Active: inactive (dead)

# cat /run/cloud-init/cloud-init-generator.log
/usr/lib/systemd/system-generators/cloud-init-generator normal=/run/systemd/generator early=/run/systemd/generator.early late=/run/systemd/generator.late
kernel command line (container[lxc]: pid 1 cmdline): /sbin/init
kernel_cmdline found unset
etc_file found disabled
already disabled: no change needed [no /run/systemd/generator.early/multi-user.target.wants/cloud-init.target]
change? This should allow existing ds-identify policy to still work, but
be overridden in the case that a user disables cloud-init as described

Yes.

in the docs. Are there any use cases that would be broken by this?

I don't think so. The policy is primarily about controlling when cloud-init
should search for datasources. In the default Ubuntu cloud-image, the
DataSource list has many entries; some of these (like say EC2, but others)
require a DHCP on an interface to find a metadata service -- ds-identify and
the policy control whether an image will attempt to search out on potentially
untrusted networks for something that looks like a known datasource.

2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.

Generally, the additional conditions in the Unit file is a workaround for not
utilzing ds-identify.

Historically there were some Distros which moved to cloud-init releases with
ds-identify but did utilize it for reasons of their choosing.

IIUC, all of the systemd files only become added as systemd Jobs if
cloud-init.target does, which should mean it's far simpler to write the
conditions in one place (the target) rather than maintain it in four
places.

Distro variants may yet still want to render in the conditions into each unit;
but as an upstream, I believe it's fine to keep them in the target.

3. The new environment variable conditional `ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled`.

+1

4. The changes in `cloud-init-generator.tmpl`

+1

Generally making the generator take less time is valuable since
systemctl daemon-reload happens far more than many realize;
keeping cloud-init's generator as light as possible is good policy.

@ani-sinha
Copy link
Contributor

ani-sinha commented Sep 4, 2023

@smoser @raharper @ani-sinha @esposem Given the invasive nature this change, I am requesting feedback from you directly on this pull request.
A few specific things I'd like to draw attention to:

  1. With this change, cloud-init now prioritizes the currently documented methods of disabling cloud-init over the ds-identify policy in all distros (formerly just RHEL) via systemd's conditional unit execution - is this acceptable behavior change? This should allow existing ds-identify policy to still work, but be overridden in the case that a user disables cloud-init as described in the docs. Are there any use cases that would be broken by this?
  2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.

This needs to be tested. We are going to test this internally.

This change does not work. This is the feedback from our QE:

  1. When touch file /etc/cloud/cloud-init.disabled, the cloud-init status is disabled, but the four cloud-init services are active, and cloud-init still runs
  2. It is same when config kernel commandline per doc https://cloudinit.readthedocs.io/en/latest/howto/disable_cloud_init.html.
    Btw, the command in the doc is wrong, it should be:
    # echo 'GRUB_CMDLINE_LINUX=”cloud-init=disable”’ >> /etc/default/grub

@ani-sinha
Copy link
Contributor

For the doc issue I sent the PR #4406 .

@raharper
Copy link
Collaborator

raharper commented Sep 4, 2023

@smoser @raharper @ani-sinha @esposem Given the invasive nature this change, I am requesting feedback from you directly on this pull request.
A few specific things I'd like to draw attention to:

  1. With this change, cloud-init now prioritizes the currently documented methods of disabling cloud-init over the ds-identify policy in all distros (formerly just RHEL) via systemd's conditional unit execution - is this acceptable behavior change? This should allow existing ds-identify policy to still work, but be overridden in the case that a user disables cloud-init as described in the docs. Are there any use cases that would be broken by this?
  2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.

This needs to be tested. We are going to test this internally.

This change does not work. This is the feedback from our QE:

1. When touch file /etc/cloud/cloud-init.disabled, the cloud-init status is disabled, but the four cloud-init services are active, and cloud-init still runs

Do you have cloud-init logs from this run?

2. It is same when config kernel commandline per doc https://cloudinit.readthedocs.io/en/latest/howto/disable_cloud_init.html.
   Btw, the command in the doc is wrong, it should be:
   `# echo 'GRUB_CMDLINE_LINUX=”cloud-init=disable”’ >> /etc/default/grub`

You're suggesting that it should be 'disable', present tense, not 'disabled', past tense?

Where in the cloud-init repo does it check for value 'disable' versus 'disabled'?

https://github.com/search?q=repo%3Acanonical%2Fcloud-init+%27disable%27&type=code

suggests only the 'byobu' module looks for disable .

A longer look for "disable" has more hits[2] but none of them look like kernel command expects the present tense, 'disable'.

  1. https://github.com/search?q=repo%3Acanonical%2Fcloud-init+%22disable%22&type=code&p=4

@ani-sinha
Copy link
Contributor

@smoser @raharper @ani-sinha @esposem Given the invasive nature this change, I am requesting feedback from you directly on this pull request.
A few specific things I'd like to draw attention to:

  1. With this change, cloud-init now prioritizes the currently documented methods of disabling cloud-init over the ds-identify policy in all distros (formerly just RHEL) via systemd's conditional unit execution - is this acceptable behavior change? This should allow existing ds-identify policy to still work, but be overridden in the case that a user disables cloud-init as described in the docs. Are there any use cases that would be broken by this?
  2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.

This needs to be tested. We are going to test this internally.

This change does not work. This is the feedback from our QE:

1. When touch file /etc/cloud/cloud-init.disabled, the cloud-init status is disabled, but the four cloud-init services are active, and cloud-init still runs

Do you have cloud-init logs from this run?

2. It is same when config kernel commandline per doc https://cloudinit.readthedocs.io/en/latest/howto/disable_cloud_init.html.
   Btw, the command in the doc is wrong, it should be:
   `# echo 'GRUB_CMDLINE_LINUX=”cloud-init=disable”’ >> /etc/default/grub`

You're suggesting that it should be 'disable', present tense, not 'disabled', past tense?

Where in the cloud-init repo does it check for value 'disable' versus 'disabled'?

You got it all wrong. Please see my PR #4406

@raharper
Copy link
Collaborator

raharper commented Sep 5, 2023

You got it all wrong. Please see my PR #4406

Your comment quoted,

Btw, the command in the doc is wrong, it should be:
# echo 'GRUB_CMDLINE_LINUX=”cloud-init=disable”’ >> /etc/default/grub

includes a typo disable which is misleading.

W.r.t to the other requests that are relevant to this PR, do you have any logs from those runs?

@ani-sinha
Copy link
Contributor

You got it all wrong. Please see my PR #4406

Your comment quoted,

Btw, the command in the doc is wrong, it should be:
# echo 'GRUB_CMDLINE_LINUX=”cloud-init=disable”’ >> /etc/default/grub

includes a typo disable which is misleading.

W.r.t to the other requests that are relevant to this PR, do you have any logs from those runs?

https://people.redhat.com/~anisinha/1108859.txt

@holmanb
Copy link
Member Author

holmanb commented Sep 6, 2023

@raharper @ani-sinha Thanks for the feedback and discussion on this PR. It seems sentiment so far is that the changes are agreeable, with the exception being the relocation of the service conditionals to the target file. Regarding that:

2. Is it safe to shift the conditional execution lines from the four .service files to cloud-init.target? This part of the change can be dropped if needed.

Generally, the additional conditions in the Unit file is a workaround for not
utilzing ds-identify.

Historically there were some Distros which moved to cloud-init releases with
ds-identify but did utilize it for reasons of their choosing.

IIUC, all of the systemd files only become added as systemd Jobs if
cloud-init.target does, which should mean it's far simpler to write the
conditions in one place (the target) rather than maintain it in four
places.

Distro variants may yet still want to render in the conditions into each unit;
but as an upstream, I believe it's fine to keep them in the target.

This was my understanding as well, but testing this now I see that the PR as it is fails to disable, as @ani-sinha reported. Re-adding these lines to the service files disables cloud-init as expected.

I'll re-add the conditions to the service files as distro-independent conditions.

It should be functionally equivalent, so I'll leave the conditions in the target file so that users can see why cloud-init is disabled in the output of systemctl status cloud-init.target.

Output with conditionals in target file:

# systemctl status cloud-init.target
○ cloud-init.target - Cloud-init target
     Loaded: loaded (/lib/systemd/system/cloud-init.target; enabled-runtime; preset: enabled)
     Active: inactive (dead)
  Condition: start condition failed at Wed 2023-09-06 17:24:21 UTC; 2min 26s ago
             └─ ConditionPathExists=!/etc/cloud/cloud-init.disabled was not met

Sep 06 17:24:21 cloudinit-0906-172247p1t9grm5 systemd[1]: cloud-init.target - Cloud-init target was skipped because of an unmet condition check (ConditionPathExists=!/etc/cloud/cloud-init.disabled).

Output without conditionals in target file:

# systemctl status cloud-init.target
○ cloud-init.target - Cloud-init target
     Loaded: loaded (/lib/systemd/system/cloud-init.target; enabled-runtime; preset: enabled)
     Active: inactive (dead)

@raharper
Copy link
Collaborator

raharper commented Sep 6, 2023

I'll re-add the conditions to the service files as distro-independent conditions.

It should be functionally equivalent, so I'll leave the conditions in the target file so that users can see why cloud-init is disabled in the output of systemctl status cloud-init.target.

From what I recall, systems which did not use ds-identify would fully install the services; that is the generator was effectively disabled and cloud-init*.service always ran no matter what; which prompted the inclusion of the conditionals.
Like this:

https://gitlab.com/redhat/centos-stream/src/cloud-init/-/blob/c9s/packages/redhat/cloud-init.spec.in?ref_type=heads#L125

With this style of install, ds-identify/generator doesn't matter as systemd itself is going to run these units on its own (systemctl enable creates symlinks to /etc/systemd/system/multi-user.target.wants/*) ; in this case, conditionals per service unit make sense.

If a distro does not systemctl enable cloud-init services; and instead lets the generator dynamically enable cloud-init.target; then no units should run if generator doesn't link cloud-init.target to multi-user.target.wants.

A few things to confirm. In @ani-sinha test, were the cloud-init units already activated (via the systemctl enable like in the specfile I link)? If so, then I believe the cloud-init.target won't affect whether the cloud-init services run since in the multi-user.wants dir, it isn't just cloud-init.target, but rather all 4 services linked.

To have cloud-init.target control the execution of the service units, cloud-init.target and only cloud-init target can be enabled (dynamically, or statically).

That is, the upstream spec file can instead do:

systemctl enable cloud-init.target

Or allow the generator to check if cloud-init.target should be added to multi-user.target.

In either case here, if cloud-init.target conditionals fail, then the other cloud-init services should not run either.
I do have a doubt/concern; it is possible that once a generator enables a target (we add the cloud-init.target symlink to multi-user.target) it could mean systemd enqueues the other targets (per the [Install] wants cloud-init.target in each service file) before systemd evaluates whether the cloud-init.target is active (per the conditionals).

If that is the case, then the conditional tests will need to remain in the generator to avoid adding cloud-init.target to multi-user.target.wants to prevent the services from running.

@holmanb
Copy link
Member Author

holmanb commented Sep 6, 2023

I do have a doubt/concern; it is possible that once a generator enables a target (we add the cloud-init.target symlink to multi-user.target) it could mean systemd enqueues the other targets (per the [Install] wants cloud-init.target in each service file) before systemd evaluates whether the cloud-init.target is active (per the conditionals).

If that is the case, then the conditional tests will need to remain in the generator to avoid adding cloud-init.target to multi-user.target.wants to prevent the services from running.

I don't think this is a concern. See the enabled cloud-init.target is disabled on reboot below due to the condition check.

root@cloudinit-0906-23040247wpwk2q:~# systemctl status cloud-init.target
● cloud-init.target - Cloud-init target
     Loaded: loaded (/lib/systemd/system/cloud-init.target; enabled-runtime; preset: enabled)
     Active: active since Wed 2023-09-06 23:24:52 UTC; 1s ago
      Until: Wed 2023-09-06 23:24:52 UTC; 1s ago

Sep 06 23:24:52 cloudinit-0906-23040247wpwk2q systemd[1]: Reached target cloud-init.target - Cloud-init target.
root@cloudinit-0906-23040247wpwk2q:~# touch /etc/cloud/cloud-init.disabled
root@cloudinit-0906-23040247wpwk2q:~# cloud-init clean --logs --reboot
root@cloudinit-0906-23040247wpwk2q:~# 

Session terminated, killing shell... ...killed.
arc~/cloud-init-d(holmanb/do-less-in-generator|…) lxc shell cloudinit-0906-23040247wpwk2q
root@cloudinit-0906-23040247wpwk2q:~# systemctl status cloud-init.target
○ cloud-init.target - Cloud-init target
     Loaded: loaded (/lib/systemd/system/cloud-init.target; static)
     Active: inactive (dead)
root@cloudinit-0906-23040247wpwk2q:~# cloud-init status --long
status: disabled
boot_status_code: disabled-by-marker-file
detail:
Cloud-init disabled by /etc/cloud/cloud-init.disabled
root@cloudinit-0906-23040247wpwk2q:~# systemctl status cloud-init
○ cloud-init.service - Initial cloud-init job (metadata service crawler)
     Loaded: loaded (/lib/systemd/system/cloud-init.service; enabled; preset: enabled)
     Active: inactive (dead)
root@cloudinit-0906-23040247wpwk2q:~# systemctl status cloud-init.target
○ cloud-init.target - Cloud-init target
     Loaded: loaded (/lib/systemd/system/cloud-init.target; static)
     Active: inactive (dead)

@ani-sinha
Copy link
Contributor

A few things to confirm. In @ani-sinha test, were the cloud-init units already activated (via the systemctl enable like in the specfile I link)? I

Yes. That is correct. My changes are here:
https://gitlab.com/anisinha/cloud-init/-/commits/PR4399/

I think we need to keep the check on individual unit files. Otherwise, with only in .target once disabled, it did not get enabled again when the check failed.
If the unit test refectoring changes are not essential, can you please revert them and keep things as they are? Testing this PR multiple times is consuming dev and QE resources - something we can't afford right now. Thanks.

@raharper
Copy link
Collaborator

raharper commented Sep 7, 2023

I do have a doubt/concern; it is possible that once a generator enables a target (we add the cloud-init.target symlink to multi-user.target) it could mean systemd enqueues the other targets (per the [Install] wants cloud-init.target in each service file) before systemd evaluates whether the cloud-init.target is active (per the conditionals).
If that is the case, then the conditional tests will need to remain in the generator to avoid adding cloud-init.target to multi-user.target.wants to prevent the services from running.

I don't think this is a concern. See the enabled cloud-init.target is disabled on reboot below due to the condition check.

Excellent! That was what I expecting but wasn't 100% sure. Thank you for testing.

@holmanb
Copy link
Member Author

holmanb commented Sep 7, 2023

I think we need to keep the check on individual unit files.

This is my plan for now with this PR.

If the unit test refectoring changes are not essential, can you please revert them and keep things as they are?

The failing unit tests are a result of fixing a bug that I uncovered while testing this code out:

Currently cloud-init supports disabling cloud-init via environment variable KERNEL_CMDLINE on containers, however this method is not captured in the status subcommand's get_bootstatus(), which means that if cloud-init is disabled via this method, a cloud-init status --wait will run indefinitely; this is unacceptable. Fixing this broke a couple of unit tests. I plan to fix shortly and then mark this PR as ready for review (no longer WIP).

Testing this PR multiple times is consuming dev and QE resources - something we can't afford right now. Thanks.

@ani-sinha Many thanks for the engagement and feedback!

@holmanb
Copy link
Member Author

holmanb commented Sep 7, 2023

Excellent! That was what I expecting but wasn't 100% sure. Thank you for testing.

@raharper Happy to, thanks for the feedback. Also note 49c56bb in this PR which includes integration test coverage for all three methods of disablement.

@holmanb holmanb changed the title WIP Proposal: Move disable checks out of systemd generator Move disable checks out of systemd generator Sep 7, 2023
Copy link
Member Author

@holmanb holmanb left a comment

Choose a reason for hiding this comment

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

Leaving a few comments to help reviewers understand the generator changes.

@@ -42,105 +42,47 @@ debug() {
echo "$@" >> "$LOG"
}

etc_file() {
Copy link
Member Author

Choose a reason for hiding this comment

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

This is now handled by ConditionPathExists.

return 0
}

read_proc_cmdline() {
Copy link
Member Author

Choose a reason for hiding this comment

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

Both container and non-container cases are handled by ConditionKernelCommandline


kernel_cmdline() {
local cmdline="" tok=""
if [ -n "${KERNEL_CMDLINE+x}" ]; then
Copy link
Member Author

Choose a reason for hiding this comment

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

KERNEL_CMDLINE is now handled by ConditionEnvironment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes and no. It is not handled from a generator perspective. If KERNEL_CMDLINE=cloud-init=disabled exists there is really nothing for the generator to do and it should just exit as systemd will handle the rest via the ConditionEnvironment setting. But this does not apply to the generator and as such dsidentify is still run, which we shouldn't really do if the user disabled cloud-init.

I think the generator should specifically look for KERNEL_CMDLINE=cloud-init=disabled and if found exit and do nothing else.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is addressed in the latest commit.

_RET="$ENABLE"
}

check_for_datasource() {
Copy link
Member Author

Choose a reason for hiding this comment

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

No need to define a function that gets called once. Function definition and subsequent lookup at invocation time have costs. Inline it.


debug 1 "$0 normal=$normal_d early=$early_d late=$late_d"
debug 2 "$0 $*"

local search result="error" ret=""
Copy link
Member Author

Choose a reason for hiding this comment

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

Setting result to $ENABLE or $DISABLE is unnecessary to accomplish this logic and adds a variable (which adds lookup time) and unnecessary branches (more time cost) and IMO is harder to read. Shift code around to avoid these conditionals and variable usage.

TL;DR: Do the same thing, with less.

debug 1 "ds-identify rc=$ds"

if [ "$ds" = "1" ]; then
debug 1 "cloud-init is enabled but no datasource found, disabling"
Copy link

@antcodd antcodd Sep 13, 2023

Choose a reason for hiding this comment

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

If a cloud-init is installed but disabled, the misleading message cloud-init is enabled but no datasource found, disabling will now be printed by the generator on boot, and ds-identify will output misleading messages attempting to detect clouds.

ds-identify will likely write incorrect /run/cloud-init/cloud.cfg configuration as if it was enabling datasources.

$RUN_ENABLED_FILE (/run/cloud-init/cloud-init.enabled/.disabled) will also be set to the wrong state. I'm not sure if this file is used for anything since dhclient hooks were removed in #2015, but it could be used as an indicator for other external scripts. cloud-init.enabled also doesn't appear to be created when not using the generator.

Copy link
Contributor

Choose a reason for hiding this comment

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

The message will only be printed if no datasource is found. This is still misleading, no question, but it is not unconditional. In the case of a "happy path", i.e. dsidentify runs and finds a data source the message will not be printed.

That said if cloud-init is disabled, why run dsitentify at all?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Even though this text in /run/cloud-init/cloud-init-generator.log is not machine readable, and I don't think we have scripts parsing and relying on the output of this file, I'd like us to specialize that message when cloud-init is disabled. Then we better represent the actual state during generator time-frame when we see cloud-init disabled and don't have to fallback to querying cloud-init status or systemctl status cloud-init.target etc to get that info.

@antcodd
Copy link

antcodd commented Sep 13, 2023

Having the cloud-init package installed but disabled will become very expensive, as ds-identify will now still run and attempt to detect clouds. On every boot ds-identify will run expensive hardware DMI detection logic as a systemd generator that synchronously blocks all of boot. This performance impact will likely dwarf any small changes from checking a few flags on each boot.

Did the benchmarking include deleting the cloud-init cached configuration from /run, as it would not be present on boot? ds-identify skips cloud detection checks when the result is cached. Generators also run any time systemctl daemon-reload is triggered, though in that case ds-identify should at least use the cached result.

I think the changes to cloud-init-generator should be reverted, or ds-identify needs to check the disabled state flags before it tries to detect clouds. I also suspect there might be more to be gained by conditionally skipping some of the logic in collect_info from ds_identify than changes to the generator itself.

Another option might be to have cloud-init-generator (and ds-identify) just run as a unit before cloud-init-local.service and check the conditions as part of the unit file? Enqueuing additional services during boot using systemctl appears to work, so long as they aren't waited on. This would also allow ds-identify to read configuration from other filesystems. This wouldn't cover new cloud-init package installation having the generator run by systemctl daemon-reload though.

@blackboxsw
Copy link
Collaborator

blackboxsw commented Sep 25, 2023

Thanks @holmanb for the refactors here and insights.

  • I agree that we want to avoid calling systemd-detect-virt multiple time in systemd-generator timeframe. And reducing some of the calls in cloud-init-generator.tmpl will cut down on the 2 separate systemd-detect-virt calls that cloud-init-generator and ds-identify make in happy path case.
  • I also agree we should be defensive in both cloud-init.target and cloud-*.service files to ensure that platforms which only deliver the systemd units instead of the cloud-init.target are able to effectively see those units inactive/disabled if neither ds-identify, nor cloud-init.target are present on the system. Thanks @raharper and @ani-sinha for confirmation about CentOS setup there.

Reducing the number of systemd-detect-virt calls as you've done here is good but I share some of the same concerns @rjschwei and @antcodd have raised that we want to NOOP as early as possible in systemd-generator timeframe when we know cloud-init is disabled. The use-cases I can think of are Live server and live desktop environments which perform installations with cloud-init and leave cloud-init in a disabled state after the post-install system first boot with the /etc/cloud/cloud-init.disabled flag file. We don't want those physical systems always re-reading DMI information at boot on every boot when we know it is declared disabled.

What I suggest is the following:
Since cloud-init-generator and ds-identify both attempt to process the kernel cmdline, and ds-identify needs to process the kernel commandline for much more than just whether cloud-init is disabled, I think it makes sense to avoid calling systemd-detect-virt in the generator script. Instead, we can extend ds-identify kernel cmdline parsing it already does to also check for cloud-init=disabled state and the /etc/cloud/cloud-init.disabled flag file.

Per @antcodd's suggestion, ds-identify can perform it's initial disabled check earlier than DMI reads. I think we can do that with with a different exit code(2) that will also resolve @antcodd's other concern about misleading messages coming from the generator, as the generator can check exit code 2 and report "cloud-init disabled due to kernel commandline or etc_file".

Here's a suggested proposal for discussion, what his does is gives ds-identify a quick exit when disabled, leaves the generator "simple" without the duplicated kernel cmdline parsing based on container/non-container environments and give avoid enabling systemd units/services in a system when cloud-init disabled by the environment.

From b40986fb29c7177e589517a6f6350b8f5fe4ccd2 Mon Sep 17 00:00:00 2001
From: Chad Smith <[email protected]>
Date: Tue, 26 Sep 2023 12:49:16 -0600
Subject: [PATCH] ds-identify: exit 2 on disabled state from marker or cmdline

The cloud-init-generator no longer checks disabled state of
cloud-init from the kernel command line or marker file in
/etc/cloud/cloud-init.disabled.

This means ds-identify will be called during systemd generator
even in disabled cases.

Given that ds-identify parses the kernel commandline for datasource
discovery, allow it to check whether cloud-init=disabled is present
in kernel command line, KERNEL_CMDLINE or
/etc/cloud/cloud-init.disabled.

Add a new exit code(2) from ds-identify to allow
cloud-init-generator to allow differentation of disabled state due
to environment artifacts versus disabled due to no detected
datasources.

Additionally, factor the minimum operations needed for detecting
if cloud-init is disabled to earlier in ds-identify to allow an early
exit before more costly DMI read operations in collect_info.
There is no need to perform all collect_info in ds-identify when
cloud-init is fully disabled by commandline or
/etc/cloud/cloud-init.disabled.
---
 systemd/cloud-init-generator.tmpl   |  8 ++++++--
 tests/unittests/test_ds_identify.py |  4 ++++
 tools/ds-identify                   | 26 +++++++++++++++++++++++---
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/systemd/cloud-init-generator.tmpl b/systemd/cloud-init-generator.tmpl
index 5999fc5d2..3c9ca1695 100644
--- a/systemd/cloud-init-generator.tmpl
+++ b/systemd/cloud-init-generator.tmpl
@@ -64,8 +64,12 @@ main() {
     ds=$?
     debug 1 "ds-identify rc=$ds"
 
-    if [ "$ds" = "1" ]; then
-        debug 1 "cloud-init is enabled but no datasource found, disabling"
+    if [ "$ds" = "1" -o "$ds" = "2" ]; then
+        if [ "$ds" = "1" ]; then
+            debug 1 "cloud-init is enabled but no datasource found, disabling"
+        else
+            debug 1 "cloud-init is disabled by kernel commandline or etc_file"
+        fi
         if [ -f "$link_path" ]; then
             if rm -f "$link_path"; then
                 debug 1 "disabled. removed existing $link_path"
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index 66dae60e4..200c488c6 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -329,6 +329,10 @@ class DsIdentifyBase(CiTestCase):
                 "ret": 1,
                 "err": "No dmidecode program. ERROR.",
             },
+            {
+                "name": "is_disabled",
+                "ret": 1,
+            },
             {
                 "name": "get_kenv_field",
                 "ret": 1,
diff --git a/tools/ds-identify b/tools/ds-identify
index 8b5229d8e..babd1f43b 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -1039,6 +1039,23 @@ has_ovf_cdrom() {
     return 1
 }
 
+is_disabled() {
+    if [ -f /etc/cloud/cloud-init.disabled ]; then
+        debug 1 "disabled by marker file /etc/cloud-init.disabled"
+        return 0
+    fi
+    if [ "${KERNEL_CMDLINE:-}" = "cloud-init=disabled" ]; then
+        debug 1 "disabled by KERNEL_CMDLINE environment variable"
+        return 0
+    fi
+    case "$DI_KERNEL_CMDLINE" in
+       *cloud-init=disabled*)
+            debug 1 "disabled by kernel command line cloud-init=disabled"
+            return 0
+    esac
+    return 1
+}
+
 dscheck_OVF() {
     check_seed_dir ovf ovf-env.xml && return "${DS_FOUND}"
 
@@ -1517,10 +1534,7 @@ dscheck_VMware() {
 }
 
 collect_info() {
-    read_uname_info
-    read_virt
     read_pid1_product_name
-    read_kernel_cmdline
     read_config
     read_datasource_list
     read_dmi_sys_vendor
@@ -1795,6 +1809,12 @@ _main() {
 
     read_uptime
     debug 1 "[up ${_RET}s]" "ds-identify $*"
+    read_uname_info
+    read_virt
+    read_kernel_cmdline
+    if is_disabled; then
+        return 2
+    fi
     collect_info
 
     if [ "$DI_LOG" = "stderr" ]; then
-- 
2.39.2

@blackboxsw
Copy link
Collaborator

Also note on Ubuntu systems we are generally seeing 15 calls to systemd-detect-virt on boot when cloud-init is enabled. Since cloud-init generator + ds-identify perform two of those calls, it'd be good to reduce one of those calls to systemd-detect-virt if both the generator wrapper and ds-identify can rely on the same single call to detect-virt to determine disabled state from the proper kernel command line. I can see with this changeset + diff we are down to 14 calls instead of 15. In cloud-init disabled case systemd-detect-virt is called 10 times.

Copy link
Collaborator

@blackboxsw blackboxsw left a comment

Choose a reason for hiding this comment

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

Marking request changes to discuss whether we can push disable awareness from kernel commandline in ds-identify since it has to parse kernel cmdline anyway in the case that cloud-init is enabled.

Comment on lines +13 to +15
ConditionPathExists=!/etc/cloud/cloud-init.disabled
ConditionKernelCommandLine=!cloud-init=disabled
ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like these additional condition checks for visibility at systemctl status cloud-init.target level, but this duplicates conditions we've decided to keep on each subordinate cloud-*.service file and we don't strictly need them if we are going to preserve the checks on the individual units. Can we measure if there is a cost to these duplicated conditions? It does make systemd dependency resolver do a little but more as far as checks for this target unit file.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll measure and report back.

Copy link
Member Author

Choose a reason for hiding this comment

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

@blackboxsw see the section in the PR description titled "Measuring with and without conditionals in .target" for the numbers

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks @holmanb. This looks good to me as well as your assessment above. Also I triggered those compound conditionals directly on the systemd-analyze conditional subcommand with comparable results. The avg time seems to be +- one millisecond with or without the 3 extra checks.

root@schema-m:~# time systemd-analyze condition 'ConditionKernelCommandLine=!cloud-init=disabled'
test.service: ConditionKernelCommandLine=!cloud-init=disabled succeeded.
Conditions succeeded.

real	0m0.007s
user	0m0.000s
sys	0m0.007s
root@schema-m:~# time systemd-analyze condition 'ConditionKernelCommandLine=!cloud-init=disabled' 'ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled' 'ConditionPathExists=!/etc/cloud/cloud-init.disabled' 'ConditionKernelCommandLine=!cloud-init=disabled' 'ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled'
test.service: ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled succeeded.
test.service: ConditionKernelCommandLine=!cloud-init=disabled succeeded.
test.service: ConditionPathExists=!/etc/cloud/cloud-init.disabled succeeded.
test.service: ConditionEnvironment=!KERNEL_CMDLINE=cloud-init=disabled succeeded.
test.service: ConditionKernelCommandLine=!cloud-init=disabled succeeded.
Conditions succeeded.

real	0m0.007s
user	0m0.000s
sys	0m0.007s

debug 1 "ds-identify rc=$ds"

if [ "$ds" = "1" ]; then
debug 1 "cloud-init is enabled but no datasource found, disabling"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Even though this text in /run/cloud-init/cloud-init-generator.log is not machine readable, and I don't think we have scripts parsing and relying on the output of this file, I'd like us to specialize that message when cloud-init is disabled. Then we better represent the actual state during generator time-frame when we see cloud-init disabled and don't have to fallback to querying cloud-init status or systemctl status cloud-init.target etc to get that info.

@blackboxsw
Copy link
Collaborator

Having the cloud-init package installed but disabled will become very expensive, as ds-identify will now still run and attempt to detect clouds. On every boot ds-identify will run expensive hardware DMI detection logic as a systemd generator that synchronously blocks all of boot. This performance impact will likely dwarf any small changes from checking a few flags on each boot.

Agreed, DMI reading is probably a fair amount of cost in ds-identify that we should probably avoid if we know we are disabled.
And, we could even go further and not even attempt to invoke systemd-detect-virt before parsing the kernel cmdline if we first check the /etc/cloud/cloud-config.disabled flag to save even more time in a disabled system.

Did the benchmarking include deleting the cloud-init cached configuration from /run, as it would not be present on boot? ds-identify skips cloud detection checks when the result is cached. Generators also run any time systemctl daemon-reload is triggered, though in that case ds-identify should at least use the cached result.

Most of ds-identify's caching is really just checks on whether variables have been defined and if so, return the cached var name. It's not disk caching that we are talking about here. The benchmarking is going to be highly platform dependent as it does go though and source DMI vars on the host in which the benchmark it is running

I think the changes to cloud-init-generator should be reverted, or ds-identify needs to check the disabled state flags before it tries to detect clouds. I also suspect there might be more to be gained by conditionally skipping some of the logic in collect_info from ds_identify than changes to the generator itself.

I disagree with the first statement as long as we can conditionally skip logic down in ds-identify.collect_info if disabled artifacts are present.

@holmanb
Copy link
Member Author

holmanb commented Sep 26, 2023

What I suggest is the following: Since cloud-init-generator and ds-identify both attempt to process the kernel cmdline, and ds-identify needs to process the kernel commandline for much more than just whether cloud-init is disabled, I think it makes sense to avoid calling systemd-detect-virt in the generator script. Instead, we can extend ds-identify kernel cmdline parsing it already does to also check for cloud-init=disabled state and the /etc/cloud/cloud-init.disabled flag file.

This seems like a fair trade-off. Since ds-identify already gathers this information it shouldn't be a measurable extra cost to the non-disabled case, and a clear improvement for the disabled case. This is a reasonable tradeoff.

Per @antcodd's suggestion, ds-identify can perform it's initial disabled check earlier than DMI reads. I think we can do that with with a different exit code(2) that will also resolve @antcodd's other concern about misleading messages coming from the generator, as the generator can check exit code 2 and report "cloud-init disabled due to kernel commandline or etc_file".

This is a slight UI change to ds-identify, but since it's a low level tool that isn't documented I would make the argument that such changes don't count as real behavior changes. Non-zero for an error condition makes sense.

Here's a suggested proposal for discussion, what his does is gives ds-identify a quick exit when disabled, leaves the generator "simple" without the duplicated kernel cmdline parsing based on container/non-container environments and give avoid enabling systemd units/services in a system when cloud-init disabled by the environment.

@blackboxsw If you can push your branch up to Github or share the formatted patch (git format-patch -1 HEAD --stdout) I'll apply this change with authorship preserved, since you did write it and I think it fits this series nicely as its own commit (albeit with a more detailed message, but I can update that if you'd rather not).

Also note on Ubuntu systems we are generally seeing 15 calls to systemd-detect-virt on boot when cloud-init is enabled. Since cloud-init generator + ds-identify perform two of those calls, it'd be good to reduce one of those calls to systemd-detect-virt if both the generator wrapper and ds-identify can rely on the same single call to detect-virt to determine disabled state from the proper kernel command line. I can see with this changeset + diff we are down to 14 calls instead of 15. In cloud-init disabled case systemd-detect-virt is called 10 times.

Nice instrumentation! Now I'm curious now which other processes are using it.

@blackboxsw
Copy link
Collaborator

@blackboxsw If you can push your branch up to Github or share the formatted patch (git format-patch -1 HEAD --stdout) I'll apply this change with authorship preserved, since you did write it and I think it fits this series nicely as its own commit (albeit with a more detailed message, but I can update that if you'd rather not).

I've updated the inline patch above w/ a more specific commit msg and also pushed https://github.com/blackboxsw/cloud-init/tree/holmanb/do-less-in-generator

Copy link
Collaborator

@blackboxsw blackboxsw left a comment

Choose a reason for hiding this comment

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

LGTM, minor nit on integration test but you don't have to hold up the PR on that. Also, please provide the (#4399) suffix to each commit if rebase merging.

Comment on lines +14 to +15
def restart_cloud_init(c):
client = c
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit:non-blocking why not just pass in a variable named client and use that.

Copy link
Member Author

Choose a reason for hiding this comment

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

since client is a fixture, I didn't want to use that name because 1) I don't know if a fixture would be invoked (non-test functions can get fixtures invoked, for example a fixture that invokes other fixtures) and 2) even if 1 doesn't occur, it might confuse a reader who might assume that it does. This is more clear in my mind, though I guess I could have just picked a different variable name.

holmanb and others added 7 commits October 9, 2023 15:07
)

Add missing cloud-init disabled state which fixes `cloud-init status
--wait` never completing when cloud-init is disabled via KERNEL_CMDLINE.
- Make all distros use systemd's kernel commandline and file conditionals
- Add ConditionEnvironment to all services and targets
- Add conditions to cloud-init.target

cloud-init-generator implements these conditional checks, but these can be
implemented in cloud-init service and target files at lower cost.
- inline function check_for_datasource()
- eliminate unnecessary variable assignments and branches
- eliminate enablement checks (made redundant by systemd conditionals)
…al#4399)

The cloud-init-generator no longer checks disabled state of
cloud-init from the kernel command line or marker file in
/etc/cloud/cloud-init.disabled.

This means ds-identify will be called during systemd generator
even in disabled cases.

Given that ds-identify parses the kernel commandline for datasource
discovery, allow it to check whether cloud-init=disabled is present
in kernel command line, KERNEL_CMDLINE or
/etc/cloud/cloud-init.disabled.

Add a new exit code(2) from ds-identify to allow
cloud-init-generator to allow differentation of disabled state due
to environment artifacts versus disabled due to no detected
datasources.

Additionally, factor the minimum operations needed for detecting
if cloud-init is disabled to earlier in ds-identify to allow an early
exit before more costly DMI read operations in collect_info.
There is no need to perform all collect_info in ds-identify when
cloud-init is fully disabled by commandline or
/etc/cloud/cloud-init.disabled.
@holmanb holmanb force-pushed the holmanb/do-less-in-generator branch from 1b5d9b4 to 8ab927a Compare October 9, 2023 21:09
@holmanb holmanb merged commit de5fc36 into canonical:main Oct 9, 2023
27 checks passed
holmanb added a commit that referenced this pull request Oct 9, 2023
Add missing cloud-init disabled state which fixes `cloud-init status
--wait` never completing when cloud-init is disabled via KERNEL_CMDLINE.
holmanb added a commit that referenced this pull request Oct 9, 2023
holmanb added a commit that referenced this pull request Oct 9, 2023
- Make all distros use systemd's kernel commandline and file conditionals
- Add ConditionEnvironment to all services and targets
- Add conditions to cloud-init.target

cloud-init-generator implements these conditional checks, but these can be
implemented in cloud-init service and target files at lower cost.
holmanb added a commit that referenced this pull request Oct 9, 2023
- inline function check_for_datasource()
- eliminate unnecessary variable assignments and branches
- eliminate enablement checks (made redundant by systemd conditionals)
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.

7 participants