The Puppet Labs Issue Tracker has Moved: https://tickets.puppetlabs.com

Bug #12173

Masters cannot reliably distinguish between multiple versions of a type/function/plugin used in different environments

Added by Nigel Kersten about 2 years ago. Updated 4 months ago.

Status:AcceptedStart date:01/25/2012
Priority:NormalDue date:
Assignee:eric sorenson% Done:

0%

Category:environments
Target version:3.x
Affected Puppet version:2.7.0 Branch:
Keywords:telly_deprecation BD customer

We've Moved!

Ticket tracking is now hosted in JIRA: https://tickets.puppetlabs.com

This ticket is now tracked at: https://tickets.puppetlabs.com/browse/PUP-731


Description

Quoted from a previous ticket, #4409

The key problem is that a master can’t reliably distinguish between two versions of the same native type that are used in different environments (or between an environment which uses a native type and an environment which doesn’t). This is due to the fact that native types are defined using ruby code, which the master loads into Ruby classes via “require”. Since there can only be one Ruby class with a given name at a time, this prevents the master from being able to have two different versions of the same type in two different environments. This makes life difficult for people who are trying to use a “test” environment to try out a new version of a native type on a limited set of nodes before deploying it to all nodes.

A secondary problem is that the location where the master looks for the definition of native types is not the same as the location of plug-in files that the master distributes to agents. This leads to confusion even for people who are not using a “test” environment, because it means that they have to put their type definitions in two places, one where they can be picked up by the master and one where they can be sent as plug-ins to agents.


Related issues

Related to Puppet - Refactor #7703: Handling of Known Resource Types data in the environment ... Accepted 05/27/2011
Related to Puppet - Refactor #16008: The RAL and Parser resource and Type classes should be re... Investigating 08/17/2012
Related to Puppet - Bug #13858: Custom types in environments require loading into master'... Closed 04/08/2012
Related to Puppet - Bug #17210: Updated functions are not reloaded within a worker process In Topic Branch Pending Review
Related to Puppet - Bug #15770: Deprecate environment configuration in puppet.conf Investigating 07/31/2012
Related to Puppet - Bug #7316: puppet face applications (subcommands) delivered via modu... Closed 05/02/2011
Related to Puppet - Bug #18042: Deprecate face versions Accepted
Related to Puppet - Bug #18154: Master and agent should not share libdir Accepted
Related to Puppet - Bug #18534: Warn when multiple versions of the same module are availa... Needs Decision
Duplicated by Puppet - Bug #21607: Custom module functions do not seem to stay within their ... Duplicate

History

#1 Updated by Nigel Kersten about 2 years ago

  • Affected Puppet version set to 2.7.0

#2 Updated by Nigel Kersten about 2 years ago

Note that #7703 is not necessary to band-aid this issue, but may be appropriate to solve to fix it more thoroughly.

#3 Updated by eric sorenson over 1 year ago

  • Assignee set to eric sorenson
  • Keywords set to telly_deprecation

The idea is that we should restrict puppet-master processes to one environment per process; it’s the only deterministic way to avoid the problem as stated.

This goes along with #15733, where anything other than the supported environment (rack with some awareness of child processes and a way to dispatch requests for an environment to its own process) would toss a deprecation warning.

#4 Updated by Dan Bode over 1 year ago

  • Keywords changed from telly_deprecation to telly_deprecation BD

#5 Updated by Erik Dalén over 1 year ago

eric sorenson wrote:

The idea is that we should restrict puppet-master processes to one environment per process; it’s the only deterministic way to avoid the problem as stated.

This goes along with #15733, where anything other than the supported environment (rack with some awareness of child processes and a way to dispatch requests for an environment to its own process) would toss a deprecation warning.

How would this work when you update a type or function within an environment? I’ve noticed that is still a problem in 3.0.1 and you have to basically restart the puppetmaster to ensure you get the new version of the function.

#6 Updated by Erik Dalén over 1 year ago

Erik Dalén wrote:

eric sorenson wrote:

The idea is that we should restrict puppet-master processes to one environment per process; it’s the only deterministic way to avoid the problem as stated.

This goes along with #15733, where anything other than the supported environment (rack with some awareness of child processes and a way to dispatch requests for an environment to its own process) would toss a deprecation warning.

How would this work when you update a type or function within an environment? I’ve noticed that is still a problem in 3.0.1 and you have to basically restart the puppetmaster to ensure you get the new version of the function.

This might be a slightly different issue actually, so I created #17210 for it.

#7 Updated by John Bollinger 12 months ago

eric sorenson wrote:

The idea is that we should restrict puppet-master processes to one environment per process; it’s the only deterministic way to avoid the problem as stated.

Are you sure about that? As the old saw goes, “any problem in computer science can be solved with enough layers of indirection.” It seems to me that this issue could be addressed by interposing per-environment classes or (Ruby) modules into which native plugins are loaded, and from which they are resolved / used. Perhaps implementing such a thing would require touching a lot of code, but given the amount of metacode in Puppet, I don’t think that’s a given.

In any case, surely it would be better to find a way to make the feature work as it was always promised to do, instead of pulling back with an “oops, no can do.”

#8 Updated by Jeff McCune 12 months ago

Are you sure about that? As the old saw goes, “any problem in computer science can be solved with enough layers of indirection.” It seems to me that this issue could be addressed by interposing per-environment classes or (Ruby) modules into which native plugins are loaded, and from which they are resolved / used. Perhaps implementing such a thing would require touching a lot of code, but given the amount of metacode in Puppet, I don’t think that’s a given.

Unfortunately we’re fairly confident process-per-environment is the least-poor way to proceed. We’d prefer to solve this using interposing per-environment classes or some other form of containment. I haven’t been able to find a suitable container in MRI though. Java has a sophisticated class loader which would be an effective tool in this problem area. Ruby lacks this level of sophistication with regard to class loading. Anonymous classes are possible in Ruby, but a way to keep track of these anonymous classes needs to be built and maintained. Furthermore, anonymous classes have an annoying property. When an anonymous class is assigned to a constant, the class assumes the identity of the constant. This seems intuitive, but Puppet refers to classes using constants all over the place, like Puppet::Type::File:

irb(main):005:0> Puppet::Type.type :file
=> Puppet::Type::File

Even if a sophisticated anonymous class manager lived behind the type class method, all of the other anonymous :file classes would be inaccessible as soon as one of them is bound to Puppet::Type::File. We’d have to re-assign the constant over and over, which is difficult because constants are not thread safe. At this point we’d have to build and manage a fairly sophisticated lock manager and we’ve made the entire system inherently thread un-safe.

This leaves us with eliminating every place where a type or provider (or any extension for that matter) class is assigned to a constant. That’s a pretty massive undertaking, especially considering the relative lack of Ruby refactoring tools and the heavy use of meta-programming inside the Puppet RAL.

Which leaves us with the process itself as the next level of abstraction… Or switching to another runtime environment for the master, like the JVM, but even then we’d need to have different jruby heaps so the efficiency benefit is unclear.

In any case, surely it would be better to find a way to make the feature work as it was always promised to do, instead of pulling back with an “oops, no can do.”

I’ve been wracking my brain for years on this one… and I’m out of fresh ideas. Do you see anything I’m overlooking with the way MRI behaves? We’re moving to 1.9.3 now, so perhaps there’s some new behavior I’m unaware of compared to 1.8.7 and earlier versions.

#9 Updated by Zachary Stern 7 months ago

  • Keywords changed from telly_deprecation BD to telly_deprecation BD customer

Also available in: Atom PDF