[PATCH 1/6] config code changes and basic puppetminions class to have func get it's host inventory and paths from puppet

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 func/commonconfig.py    |   10 +++-
 func/overlord/client.py |  184 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 191 insertions(+), 3 deletions(-)

diff --git a/func/commonconfig.py b/func/commonconfig.py
index 3823d39..c71138d 100644
--- a/func/commonconfig.py
+++ b/func/commonconfig.py
@@ -29,10 +29,18 @@ class FuncdConfig(BaseConfig):
     minion_name = Option('')
     
     method_log_dir = Option("/var/log/func/methods/")
+    ca_file = Option('')
+    cert_file = Option('')
+    key_file = Option('')
 
 class OverlordConfig(BaseConfig):
     socket_timeout = FloatOption(0)
     backend = Option('conf')
     group_db = Option('')
-
+    key_file = Option('')
+    cert_file = Option('')
+    ca_file = Option('')
+    puppet_minions = BoolOption(False)
+    puppet_inventory = Option('/var/lib/puppet/ssl/ca/inventory.txt')
+    puppet_crl = Option('/var/lib/puppet/ssl/ca/ca_crl.pem')
 
diff --git a/func/overlord/client.py b/func/overlord/client.py
index e011929..b0631e7 100644
--- a/func/overlord/client.py
+++ b/func/overlord/client.py
@@ -18,6 +18,10 @@ import sys
 import glob
 import os
 import time
+import shlex
+import subprocess
+import re
+import fnmatch
 import func.yaml as yaml
 
 from certmaster.commonconfig import CMConfig
@@ -221,6 +225,176 @@ class Minions(object):
         return False
 
 
+class PuppetMinions(object):
+    def __init__(self, spec, port=51234, 
+                 noglobs=None, verbose=None,
+                 just_fqdns=False, groups_backend="conf",
+                 delegate=False, minionmap={},exclude_spec=None,**kwargs):
+
+        # open inventory.txt
+        # for each CN (uniqued) in there
+        # open the ca_crl.pem file  - if the serial of the CN shows up in there
+        # remove those from the list of hosts
+        
+        self.spec = spec
+        self.port = port
+        self.noglobs = noglobs
+        self.verbose = verbose
+        self.just_fqdns = just_fqdns
+        self.delegate = delegate
+        self.minionmap = minionmap
+        self.exclude_spec = exclude_spec
+
+        self.cm_config = read_config(CONFIG_FILE, CMConfig)
+        self.overlord_config = read_config(OVERLORD_CONFIG_FILE, OverlordConfig)
+        self.cm_config = read_config(CONFIG_FILE, CMConfig)        
+        self.group_class = groups.Groups(backend=groups_backend,**kwargs)
+        
+        #lets make them sets so we dont loop again and again
+        self.all_hosts = set()
+        self.all_certs = set()
+        self.all_urls = []
+
+    def _get_new_hosts(self):
+        self.new_hosts = self._get_group_hosts(self.spec)
+        return self.new_hosts
+
+    def _get_group_hosts(self,spec):
+        return self.group_class.get_hosts_by_group_glob(spec)
+
+    def _get_hosts_for_specs(self,seperate_gloobs):
+        """
+        Gets the hosts and certs for proper spec
+        """
+        tmp_hosts = set()
+        tmp_certs = set()
+        for each_gloob in seperate_gloobs:
+            if each_gloob.startswith('@'):
+                continue
+            h,c = self._get_hosts_for_spec(each_gloob)
+            tmp_hosts = tmp_hosts.union(h)
+            tmp_certs = tmp_certs.union(c)
+
+        return tmp_hosts,tmp_certs
+
+    def _get_hosts_for_spec(self,each_gloob):
+        """
+        Pull only for specified spec
+        """
+        #these will be returned
+        tmp_certs = set()
+        tmp_hosts = set()
+        
+        # revoked certs
+        revoked_serials = self._return_revoked_serials(self.overlord_config.puppet_crl)
+        # get all hosts
+        if os.access(self.overlord_config.puppet_inventory, os.R_OK):
+            fo = open(self.overlord_config.puppet_inventory, 'r')
+            host_inv = {}
+            time_format = '%Y-%m-%dT%H:%M:%S%Z'
+            now = time.time()
+            for line in fo.readlines():
+                if re.match('\s*(#|$)', line):
+                    continue
+                (serial, before, after, cn) = line.split()
+                if int(serial, 16) in revoked_serials:
+                    continue
+                before = time.strftime('%s', time.strptime(before, time_format))
+                if now < int(before):
+                    continue
+                after = time.strftime('%s', time.strptime(after, time_format))
+                if now > int(after):
+                    continue
+
+                hn = cn.replace('/CN=','')
+                hn = hn.replace('\n','')
+                if hn in host_inv:
+                    if host_inv[hn] > serial:
+                        continue
+                host_inv[hn] = serial
+
+            for hostname in host_inv.keys():
+                if fnmatch.fnmatch(hostname, each_gloob):
+                    tmp_hosts.add(hostname)
+                    # don't return certs path - just hosts
+
+        return tmp_hosts,tmp_certs
+
+    def _return_revoked_serials(self, crlfile):
+        call = '/usr/bin/openssl crl -text -noout -in %s' % crlfile
+        call = shlex.split(call)
+        serials = []
+        (res,err) = subprocess.Popen(call, stdout=subprocess.PIPE).communicate()
+        for line in res.split('\n'):
+            if line.find('Serial Number:') == -1:
+                continue
+            (crap, serial) = line.split(':')
+            serial = serial.strip()
+            serial = int(serial, 16)
+            serials.append(serial)  
+        return serials
+
+    def get_hosts_for_spec(self,spec):
+        """
+        Be careful when editting that method it will be used
+        also by groups api to pull machines to have better
+        glob control there ...
+        """
+        return self._get_hosts_for_spec(spec)[0]
+
+
+
+    def _get_all_hosts(self):
+        """
+        Gets hosts that are included and excluded by user
+        a better orm like spec so user may say 
+        func "*" --exclude "www.*;@mygroup" ...
+        """
+        included_part = self._get_hosts_for_specs(self.spec.split(";")+self.new_hosts)
+        self.all_certs=self.all_certs.union(included_part[1])
+        self.all_hosts=self.all_hosts.union(included_part[0])
+        #excluded ones
+        if self.exclude_spec:
+            #get first groups ypu dont want to run :
+            group_exclude = self._get_group_hosts(self.exclude_spec)
+            excluded_part = self._get_hosts_for_specs(self.exclude_spec.split(";")+group_exclude)
+            self.all_certs = self.all_certs.difference(excluded_part[1])
+            self.all_hosts = self.all_hosts.difference(excluded_part[0])
+
+
+
+    def get_all_hosts(self):
+        """
+        Get current host list
+        """
+        self._get_new_hosts()
+        self._get_all_hosts()
+
+        #we keep it all the time as a set so 
+        return list(self.all_hosts)
+
+    def get_urls(self):
+        self._get_new_hosts()
+        self._get_all_hosts()
+        for host in self.all_hosts:
+            if not self.just_fqdns:
+                self.all_urls.append("https://%s:%s"; % (host, self.port))
+            else:
+                self.all_urls.append(host)  
+        
+        if self.verbose and len(self.all_urls) == 0:
+            sys.stderr.write("no hosts matched\n")
+
+        return self.all_urls
+
+    # FIXME: hmm, dont like this bit of the api... -al;
+    def is_minion(self):
+        self.get_urls()
+        if len(self.all_urls) > 0:
+            return True
+        return False
+
+
 
 # does the hostnamegoo actually expand to anything?
 def is_minion(minion_string):
@@ -292,8 +466,14 @@ class Overlord(object):
         
         #overlord_query stuff
         self.overlord_query = OverlordQuery()
-
-        self.minions_class = Minions(self.server_spec, port=self.port, noglobs=self.noglobs, verbose=self.verbose,exclude_spec=self.exclude_spec)
+        if self.overlord_config.puppet_minions:
+            mc = PuppetMinions
+        else:
+            mc = Minions
+            
+        self.minions_class = mc(self.server_spec, port=self.port, 
+                                noglobs=self.noglobs, verbose=self.verbose, 
+                                exclude_spec=self.exclude_spec)
         self.minions = self.minions_class.get_urls()
         if len(self.minions) == 0:
             raise Func_Client_Exception, 'Can\'t find any minions matching \"%s\". ' % self.server_spec
-- 
1.6.6

_______________________________________________
Func-list mailing list
Func-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/func-list

[Index of Archives]     [Fedora Users]     [Linux Networking]     [Fedora Legacy List]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]

  Powered by Linux