Issue #7749 has been updated by Daniel Pittman.

> Can you be a bit more specific about what’s happening that’s a problem?

I can, indeed.

> What’s the code in CommandLine and Application that has to run before core
> is loaded? Is this a fundamental flaw, or a happenstance of implementation?

This is happenstance; I can't see any compelling reason we *must*
behave the way we currently do, although my gut feeling is that it
will be complicated to get to different behaviour.  (Also, perhaps a
little of this is always unavoidable; something, somewhere will have
to bootstrap at some time.)

Further, I think that a lot of this complexity accreted over time.  It
probably started quite reasonably, years back, and as we added more
capabilities, merged to the single binary, and modified our bootstrap
process we ended up in this position.  It has all the hallmarks of
code flow that should have been cleaned up along the way and, for
various good reasons like time pressure, just wasn't.

I can't give you an assurance that I have a perfect understanding of
all the code.  Parts of this are a black box, where I understood just
enough to know what behaviour was occurring at a very high level,
without understanding the ramifications fully.  I do know enough to
explain the obvious tip of the potential iceberg here.  (...or, it
could be this shallow.  I /think/ it is, but I can't be sure without a
lot more time.)

So, the core problem is that when you `require 'puppet'` you
implicitly *run* the code in `puppet/defaults.rb` in the context of
the top level `Puppet` module.  That, in turn, has dependencies on the
`run_mode` and/or does setup for the defaults based on the application
that is running.

Meanwhile, in `Puppet::Util::CommandLine` we actually load the
application in the `execute` *instance* method.  Loading the
application file causes the desired `run_mode` to be declared - this
is done at the time the file is loaded.  The next thing that the
`execute` method does is create an instance of the application class.

In the `Puppet::Application` initialize method a small set of things
happen: we require the command line file, store that away, then call
`set_run_mode` with the `run_mode` we stashed away earlier, at load
time.  (Here, of course, we are in execution time.)

Then, finally, that method will call `require "puppet"` *after* doing
all the rest of the setup.  This, in our bootstrap process, is when we
load the top level class, and so evaluate the defaults: triggered at
"load" time, but with that loading deliberately delayed until a bunch
of "execution" time code has run to configure global state.

I introduced the problem by requiring puppet at the time the command
line stuff was loaded, long before the code was executed and the
objects instantiated that actually configured the global state of the
code.  This led to invalid values for various settings, breaking
startup in limited ways that showed up in our acceptance tests.


To fix this, we should make sure that it is possible to just execute
`require "puppet"` as the very first line of whatever loads the puppet
code; that, in turn, implies that any library we write can just
require the top level puppet module if they depend on it.

To get there, I can identify that we need to at least disambiguate the
way we handle building the defaults, and the way they interact with
the `run_mode`.  On the plus side, this *also* means that it should be
possible to change `run_mode` at runtime without any risk of things
going wrong. :)
----------------------------------------
Refactor #7749: Bootstrapping Puppet in Ruby code has nasty scope cycles...
https://projects.puppetlabs.com/issues/7749

Author: Daniel Pittman
Status: Unreviewed
Priority: Normal
Assignee: 
Category: 
Target version: 
Affected Puppet version: 
Keywords: 
Branch: 


So, in debugging an issue using code during early startup of Puppet, I found 
out that we have some very strange run-scope dependencies in bootstrapping.

Specifically, we depend on *runtime* code in `Puppet::Util::CommandLine` and 
`Puppet::Application` executing before we can safely execute *load* time code 
in `Puppet`.

This manifests as strange defaults in the configuration, because the run mode 
is configured in P::A during that run-scope code, but the defaults load in 
puppet earlier than that.

This also makes it difficult to just `require 'puppet'` and have things 
actually work.  Coupled with a desire to be able to change run mode on the fly, 
and a longer term need for things that Faces abstract over to act as if in a 
run mode without the current hard-coded dependency, we kind of need to get this 
resolved.


-- 
You have received this notification because you have either subscribed to it, 
or are involved in it.
To change your notification preferences, please click here: 
http://projects.puppetlabs.com/my/account

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Bugs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-bugs?hl=en.

Reply via email to