Combining stages with hiera

251 views
Skip to first unread message

Jordan Wright

unread,
Feb 18, 2014, 4:34:46 PM2/18/14
to puppet...@googlegroups.com
I have some Windows systems that I need to configure a user's profile. The user has to be logged into for the profile to be created. I came up with the solution below but it seems kinda hacky. I assume there is a better way to get the same effect without having a class inside a class? Is there a way to set a stage on a class when using hiera? 

I am using Windows 7 x64, Puppet Open Source 3.4.2, and Hiera 1.3.1

autologon.pp manifest

class autologon ($username, $password) {
    stage { 'user-creation':
        before => Stage['main'],
    }
    class {'autologon-internal':
        stage => user-creation,
        username => $username,
        password => $password,
    }
    reboot { 'user-creation':
        subscribe => Stage['user-creation']
    }
    
    class autologon-internal ($username, $password) {
        user { $username:
            ensure => present,
            groups => 'Users',
            membership => inclusive,
            password => $password,
        }
        registry_value { "HKLM\\software\\microsoft\\windows nt\\currentversion\\winlogon\\defaultusername":
            ensure => present,
            type   => string,
            data   => $username,
        }
        registry_value { "HKLM\\software\\microsoft\\windows nt\\currentversion\\winlogon\\defaultdomainname":
            ensure => present,
            type   => string,
            data   => $hostname,
        }
        registry_value { "HKLM\\software\\microsoft\\windows nt\\currentversion\\winlogon\\defaultpassword":
            ensure => present,
            type   => string,
            data   => $password,
        }
        registry_value { "HKLM\\software\\microsoft\\windows nt\\currentversion\\winlogon\\autoadminlogon":
            ensure => present,
            type   => string,
            data   => '1',
        }
    }
}

hiera yaml file

---
classes:
  - autologon

autologon::username: "myusername"
autologon::password: "mypassword"

jcbollinger

unread,
Feb 19, 2014, 10:39:01 AM2/19/14
to puppet...@googlegroups.com


On Tuesday, February 18, 2014 3:34:46 PM UTC-6, Jordan Wright wrote:
I have some Windows systems that I need to configure a user's profile. The user has to be logged into for the profile to be created. I came up with the solution below but it seems kinda hacky.


Indeed.

 
I assume there is a better way to get the same effect without having a class inside a class?


It is perfectly normal for one class to declare another.  It is poor form these days, and never necessary, to nest one class definition inside another.  The best way to avoid the latter is to put your classes in a module and lay it out in the normal way.  See http://docs.puppetlabs.com/puppet/3/reference/modules_fundamentals.html, especially the "Module Layout" section.  Puppet will then automagically find the class definition corresponding to each class declaration.

 
Is there a way to set a stage on a class when using hiera? 


Sure.  The 'stage' parameter takes an ordinary string value, which hiera can provide.  You can either use automatic data binding, or explicit hiera calls.  The latter might look like this:

class { 'autologon::autologon-internal':
  stage => hiera('autologon::autologon-internal::stage'),
  ...
}
 
I don't think that really gains you anything, though.  Why would it be helpful -- or even advisable -- to set the run stage via hiera data?

Also, what do you need a run stage for, anyway?  Do you intend to put more classes in it later?  For just the one class, you could achieve effect without stages:

class autologon ($username, $password) {
    class {'autologon::autologon-internal':

        username => $username,
        password => $password,
    }
    reboot { 'user-creation':
        subscribe => Class['autologon::autologon-internal']
    }

    ...
}



I am using Windows 7 x64, Puppet Open Source 3.4.2, and Hiera 1.3.1



And I suppose you are running masterless, via 'puppet apply'.  What you have now makes some sense for such a context, but not so much for a master/agent setup.

 


I have serious concerns about this general strategy, though some of them may be mitigated by the context in which you plan to use it.  First, autologon is mildly evil in and of itself.  If you nevertheless intend to leave these systems set up with autologon enabled then ok, but if that would be an issue then you are playing with fire.  If you insist on playing with fire then your approach is incomplete: it needs a way to detect whether autologon is needed, a way to proactively disable it when unneeded, and a way to force the erstwhile autologon user to be logged out once his profile is configured.

Furthermore, if either now or in the future you will need to configure multiple profiles on the same machine, then your general approach is inadequate.  You can only configure one autologon user at a time, so you need some way to detect which among your multiple profiles need to be created, and to set each in turn for autologon.  It is probably doable, but eww.  And then, too, Puppet will need to reboot the machine once for each missing profile.  And you had better make sure that Puppet will never do this when the machine is in use.  And no, scheduling is not in general an adequate solution to that issue.

If you are running Puppet as a daemon, and you can accommodate the profile not being configured until some time (up to about Puppet's run interval) after the user first logs in, then you can avoid all the autologon and rebooting nonsense.  Instead, let Puppet configure the profile only if it exists.  That should be much simpler.

Alternatively, if you are on a domain then you could consider using roaming profiles.  Or, if you have some suitable machine under your control on which you could create a profile for the user(s), then you might be able to use the User State Migration Tool to create a copy of that profile that you can subsequently install on other machines without the user logging on.  (Don't ask me for details on that last; I'm just echoing a suggestion from here: http://community.spiceworks.com/topic/247395-create-a-user-profile-without-logon).


John

Jordan Wright

unread,
Feb 19, 2014, 3:23:58 PM2/19/14
to puppet...@googlegroups.com

I guess I should explain my situation a bit. The intent of this system is to configure kisok type systems. Each machine will be logged into a local limited user account that is running an application that the public will use. At this time I have no need and don't ever plan to have two local accounts on the machines. They are connected to the domain so any maintenance will be done via domain credentials. 


On Wednesday, February 19, 2014 10:39:01 AM UTC-5, jcbollinger wrote:


On Tuesday, February 18, 2014 3:34:46 PM UTC-6, Jordan Wright wrote:
I have some Windows systems that I need to configure a user's profile. The user has to be logged into for the profile to be created. I came up with the solution below but it seems kinda hacky.


Indeed.

 
I assume there is a better way to get the same effect without having a class inside a class?


It is perfectly normal for one class to declare another.  It is poor form these days, and never necessary, to nest one class definition inside another.  The best way to avoid the latter is to put your classes in a module and lay it out in the normal way.  See http://docs.puppetlabs.com/puppet/3/reference/modules_fundamentals.html, especially the "Module Layout" section.  Puppet will then automagically find the class definition corresponding to each class declaration.

 

That is true. I didn't think about moving it into its own file. That would make it nicer.
 
Is there a way to set a stage on a class when using hiera? 


Sure.  The 'stage' parameter takes an ordinary string value, which hiera can provide.  You can either use automatic data binding, or explicit hiera calls.  The latter might look like this:

class { 'autologon::autologon-internal':
  stage => hiera('autologon::autologon-internal::stage'),
  ...
}
 
I don't think that really gains you anything, though.  Why would it be helpful -- or even advisable -- to set the run stage via hiera data? 

I was more thinking about a way to not have a wrapper class. But after thinking about it for a day, having a wrapper class isn't as ugly as I initially thought.
 
Also, what do you need a run stage for, anyway?  Do you intend to put more classes in it later?  For just the one class, you could achieve effect without stages:

class autologon ($username, $password) {
    class {'autologon::autologon-internal':
        username => $username,
        password => $password,
    }
    reboot { 'user-creation':
        subscribe => Class['autologon::autologon-internal']
    }

    ...
}

 

I have many other classes, I just didn't hit this issue sooner because I was testing on a machine with the user already created. Many of the others touch the registry of the user, hence why the profile has to exist. After solving this issue I ran into another one where I had to put conditionals around all the registry resources anyway since the path is invalid if the current user isn't logged in. This is caused by another hack of using HKU and the SID (https://ask.puppetlabs.com/question/4425/access-the-registry-of-the-current-user-in-windows/). If the puppetlabs/registry module implements support for HKU (https://tickets.puppetlabs.com/browse/MODULES-422) then I won't need that work around. I could leave the conditionals and remove the stages but I sorta like the stages since it makes it very clear that the user has to be created first.
 

I am using Windows 7 x64, Puppet Open Source 3.4.2, and Hiera 1.3.1



And I suppose you are running masterless, via 'puppet apply'.  What you have now makes some sense for such a context, but not so much for a master/agent setup.

 

I am actually running a client/server setup.

jcbollinger

unread,
Feb 20, 2014, 10:28:04 AM2/20/14
to puppet...@googlegroups.com


On Wednesday, February 19, 2014 2:23:58 PM UTC-6, Jordan Wright wrote:

I guess I should explain my situation a bit.


The bottom line seems to be that the systems being configured are intended to have exactly one local account in their final state, with autologon enabled on that account, and the problem is to configure the profile of that one account.  In order to configure that profile via Puppet running on the target node, it is necessary for the user to be logged in.

The general approach you have chosen seems fine for those particulars, though I do still think that you should consider using a domain account with a roaming profile instead of local accounts.  By all means, however, do arrange your classes in modules, and do not nest them.

As for run stages, these have some hidden costs related to creating unneeded and sometimes unwanted relationships between resources, and they somehow seem to have more appeal to users than I think is warranted.  Nevertheless, what you want to do with them -- ensure that the intended user is configured for autologon and is, in fact, logged on -- is a pretty reasonable use.  That's especially so given that your 'user-creation' stage must reboot the system if it updates anything.  It is still the case that anything you can do in Puppet with run stages you can also do without, but I'm not going to quibble over whether you should or should not use them for the example you presented.


John

Reply all
Reply to author
Forward
0 new messages