def refresh_slice_vinit(self): code=self.initscript sliver_initscript="/vservers/%s/etc/rc.d/init.d/vinit.slice"%self.name if tools.replace_file_with_string(sliver_initscript,code,remove_if_empty=True,chmod=0755): if code: logger.log("vsliver_vs: %s: Installed new initscript in %s"%(self.name,sliver_initscript)) if self.is_running(): # Only need to rerun the initscript if the vserver is # already running. If the vserver isn't running, then the # initscript will automatically be started by # /etc/rc.d/vinit when the vserver is started. self.rerun_slice_vinit() else: logger.log("vsliver_vs: %s: Removed obsolete initscript %s"%(self.name,sliver_initscript))
def install_and_enable_vinit (self): vinit_source="/usr/share/NodeManager/sliver-initscripts/vinit" vinit_script="/vservers/%s/etc/rc.d/init.d/vinit"%self.name rc3_link="/vservers/%s/etc/rc.d/rc3.d/S99vinit"%self.name rc3_target="../init.d/vinit" # install in sliver code=file(vinit_source).read() if tools.replace_file_with_string(vinit_script,code,chmod=0755): logger.log("vsliver_vs: %s: installed generic vinit rc script"%self.name) # create symlink for runlevel 3 if not os.path.islink(rc3_link): try: logger.log("vsliver_vs: %s: creating runlevel3 symlink %s"%(self.name,rc3_link)) os.symlink(rc3_target,rc3_link) except: logger.log_exc("vsliver_vs: %s: failed to create runlevel3 symlink %s"%rc3_link)
def manage_hmac(plc, sliver): hmac = find_tag(sliver, 'hmac') if not hmac: # let python do its thing random.seed() d = [random.choice(string.letters) for x in xrange(32)] hmac = "".join(d) SetSliverTag(plc, sliver['name'], 'hmac', hmac) logger.log("sliverauth: %s: setting hmac" % sliver['name']) path = '/vservers/%s/etc/planetlab' % sliver['name'] if os.path.exists(path): keyfile = '%s/key' % path if (tools.replace_file_with_string(keyfile, hmac, chmod=0400)): logger.log("sliverauth: (over)wrote hmac into %s " % keyfile)
def manage_hmac (plc, sliver): hmac = find_tag (sliver, 'hmac') if not hmac: # let python do its thing random.seed() d = [random.choice(string.letters) for x in xrange(32)] hmac = "".join(d) SetSliverTag(plc,sliver['name'],'hmac',hmac) logger.log("sliverauth: %s: setting hmac" % sliver['name']) path = '/vservers/%s/etc/planetlab' % sliver['name'] if os.path.exists(path): keyfile = '%s/key' % path if (tools.replace_file_with_string(keyfile,hmac,chmod=0400)): logger.log ("sliverauth: (over)wrote hmac into %s " % keyfile)
def install_and_enable_vinit_for_init(self): """ suitable for init-based VMs """ vinit_source = "/usr/share/NodeManager/sliver-initscripts/vinit" vinit_script = "/vservers/%s/etc/rc.d/init.d/vinit" % self.name enable_link = "/vservers/%s/etc/rc.d/rc3.d/S99vinit" % self.name enable_target = "../init.d/vinit" # install in sliver with open(vinit_source) as f: code = f.read() if tools.replace_file_with_string(vinit_script, code, chmod=0o755): logger.log("Initscript: %s: installed generic vinit rc script" % self.name) # create symlink for runlevel 3 if not os.path.islink(enable_link): try: logger.log("Initscript: %s: creating runlevel3 symlink %s" % (self.name, enable_link)) os.symlink(enable_target, enable_link) except: logger.log_exc("Initscript failed to create runlevel3 symlink %s" % enable_link, name=self.name)
def configure(self, rec): # install or remove the slice inistscript, as instructed by the initscript tag new_initscript = rec['initscript'] if new_initscript == self.initscript: return logger.log("initscript.configure {}".format(self.name)) self.initscript = new_initscript code = self.initscript sliver_initscript = "/vservers/%s/etc/rc.d/init.d/vinit.slice" % self.name if tools.replace_file_with_string(sliver_initscript, code, remove_if_empty=True, chmod=0o755): if code: logger.log("Initscript: %s: Installed new initscript in %s" % (self.name, sliver_initscript)) if self.is_running(): # Only need to rerun the initscript if the vserver is # already running. If the vserver isn't running, then the # initscript will automatically be started by # /etc/rc.d/vinit when the vserver is started. self.rerun_slice_vinit() else: logger.log("Initscript: %s: Removed obsolete initscript %s" % (self.name, sliver_initscript))
def install_and_enable_vinit_for_systemd(self): """ suitable for systemd-based VMs """ ########## ########## initscripts : current status - march 2015 ########## # # the initscripts business worked smoothly up to f18 inclusive # with f20 and the apparition of machinectl, things started to # behave really weird # # so starting with f20, after having tried pretty hard to get this right, # but to no success obviously, and in order to stay on the safe side # of the force, I am turning off the initscript machinery completely # that is to say: the vinit.service does not get installed at all # if os.path.isfile('/usr/bin/machinectl'): logger.log("WARNING: initscripts are not supported anymore in nodes that have machinectl") return vinit_source = "/usr/share/NodeManager/sliver-systemd/vinit.service" vinit_unit_file = "/vservers/%s/usr/lib/systemd/system/vinit.service" % self.name enable_link = "/vservers/%s/etc/systemd/system/multi-user.target.wants/vinit.service" % self.name enable_target = "/usr/lib/systemd/system/vinit.service" # install in sliver with open(vinit_source) as f: code = f.read() if tools.replace_file_with_string(vinit_unit_file, code, chmod=0o755): logger.log("Initscript: %s: installed vinit.service unit file" % self.name) # create symlink for enabling this unit if not os.path.islink(enable_link): try: logger.log("Initscript: %s: creating enabling symlink %s" % (self.name, enable_link)) os.symlink(enable_target, enable_link) except: logger.log_exc("Initscript failed to create enabling symlink %s" % enable_link, name=name)
def GetSlivers(data, conf=None, plc=None): if 'accounts' not in data: logger.log_missing_data("specialaccounts.GetSlivers", 'accounts') return for account in data['accounts']: name = account['name'] new_keys = account['keys'] logger.log('specialaccounts: dealing with account %s' % name) # look up account name, which must exist pw_info = pwd.getpwnam(name) uid = pw_info[2] gid = pw_info[3] pw_dir = pw_info[5] # populate account's .ssh/authorized_keys file dot_ssh = os.path.join(pw_dir, '.ssh') #~/.ssh if not os.access(dot_ssh, os.F_OK): os.mkdir(dot_ssh) #mkdir ~/.ssh auth_keys = os.path.join(dot_ssh, 'authorized_keys') #=~/.ssh/authorized_keys # catenate all keys in string, add newlines just in case (looks like keys already have this, but) auth_keys_contents = '\n'.join(new_keys) + '\n' changes = tools.replace_file_with_string(auth_keys, auth_keys_contents) if changes: logger.log("specialaccounts: keys file changed: %s" % auth_keys) # always set permissions properly os.chmod(dot_ssh, 0700) os.chown(dot_ssh, uid, gid) os.chmod(auth_keys, 0600) os.chown(auth_keys, uid, gid) logger.log('specialaccounts: installed ssh keys for %s' % name)
def GetSlivers(data, conf = None, plc = None): if 'accounts' not in data: logger.log_missing_data("specialaccounts.GetSlivers",'accounts') return for account in data['accounts']: name = account['name'] new_keys = account['keys'] logger.log('specialaccounts: dealing with account %s'%name) # look up account name, which must exist pw_info = pwd.getpwnam(name) uid = pw_info[2] gid = pw_info[3] pw_dir = pw_info[5] # populate account's .ssh/authorized_keys file dot_ssh = os.path.join(pw_dir,'.ssh') if not os.access(dot_ssh, os.F_OK): os.mkdir(dot_ssh) auth_keys = os.path.join(dot_ssh,'authorized_keys') # catenate all keys in string, add newlines just in case (looks like keys already have this, but) auth_keys_contents = '\n'.join(new_keys)+'\n' changes = tools.replace_file_with_string(auth_keys,auth_keys_contents) if changes: logger.log("specialaccounts: keys file changed: %s" % auth_keys) # always set permissions properly os.chmod(dot_ssh, 0700) os.chown(dot_ssh, uid,gid) os.chmod(auth_keys, 0600) os.chown(auth_keys, uid,gid) logger.log('specialaccounts: installed ssh keys for %s' % name)
def GetSlivers(data, conf=None, plc=None): logger.log("omf_resctl.GetSlivers") if 'accounts' not in data: logger.log_missing_data("omf_resctl.GetSlivers", 'accounts') return try: xmpp_server = data['xmpp']['server'] if not xmpp_server: # we have the key but no value, just as bad raise Exception except: # disabled feature - bailing out logger.log( "omf_resctl: PLC_OMF config unsufficient (not enabled, or no server set), -- plugin exiting" ) return hostname = data['hostname'] def is_omf_friendly(sliver): for chunk in sliver['attributes']: if chunk['tagname'] == 'omf_control': return True for sliver in data['slivers']: # skip non OMF-friendly slices if not is_omf_friendly(sliver): continue slicename = sliver['name'] expires = str(sliver['expires']) yaml_template = config_ple_template yaml_contents = yaml_template\ .replace('_xmpp_server_',xmpp_server)\ .replace('_slicename_',slicename)\ .replace('_hostname_',hostname)\ .replace('_expires_',expires) yaml_full_path = "/vservers/%s/%s" % (slicename, yaml_slice_path) yaml_full_dir = os.path.dirname(yaml_full_path) if not os.path.isdir(yaml_full_dir): try: os.makedirs(yaml_full_dir) except OSError: pass config_changes = tools.replace_file_with_string( yaml_full_path, yaml_contents) logger.log("yaml_contents length=%d, config_changes=%r" % (len(yaml_contents), config_changes)) # would make sense to also check for changes to authorized_keys # would require saving a copy of that some place for comparison # xxx todo keys_changes = False if config_changes or keys_changes: # instead of restarting the service we call a companion script try: fetch_trigger_script_if_missing(slicename) # the trigger script actually needs to be run in the slice context of course # in addition there is a requirement to pretend we run as a login shell # hence sudo -i slice_command = ["sudo", "-i", omf_rc_trigger_script] to_run = tools.command_in_slice(slicename, slice_command) log_filename = "/vservers/%s/%s" % (slicename, omf_rc_trigger_log) logger.log("omf_resctl: starting %s" % to_run) logger.log("redirected into %s" % log_filename) logger.log("*not* waiting for completion..") with open(log_filename, "a") as log_file: subprocess.Popen(to_run, stdout=log_file, stderr=subprocess.STDOUT) # a first version tried to 'communicate' on that subprocess instance # but that tended to create deadlocks in some cases # causing nodemanager to stall... # we're only losing the child's retcod, no big deal except: import traceback traceback.print_exc() logger.log_exc("omf_resctl: WARNING: Could not call trigger script %s"%\ omf_rc_trigger_script, name=slicename) else: logger.log("omf_resctl: %s: omf_control'ed sliver has no change" % slicename)
def GetSlivers(data, conf = None, plc = None): logger.log("omf_resctl.GetSlivers") if 'accounts' not in data: logger.log_missing_data("omf_resctl.GetSlivers", 'accounts') return try: xmpp_server=data['xmpp']['server'] if not xmpp_server: # we have the key but no value, just as bad raise Exception except: # disabled feature - bailing out logger.log("omf_resctl: PLC_OMF config unsufficient (not enabled, or no server set), -- plugin exiting") return hostname = data['hostname'] def is_omf_friendly (sliver): for chunk in sliver['attributes']: if chunk['tagname']=='omf_control': return True for sliver in data['slivers']: # skip non OMF-friendly slices if not is_omf_friendly (sliver): continue slicename=sliver['name'] expires=str(sliver['expires']) yaml_template = config_ple_template yaml_contents = yaml_template\ .replace('_xmpp_server_', xmpp_server)\ .replace('_slicename_', slicename)\ .replace('_hostname_', hostname)\ .replace('_expires_', expires) yaml_full_path="/vservers/%s/%s"%(slicename, yaml_slice_path) yaml_full_dir=os.path.dirname(yaml_full_path) if not os.path.isdir(yaml_full_dir): try: os.makedirs(yaml_full_dir) except OSError: pass config_changes=tools.replace_file_with_string(yaml_full_path, yaml_contents) logger.log("yaml_contents length=%d, config_changes=%r"%(len(yaml_contents), config_changes)) # would make sense to also check for changes to authorized_keys # would require saving a copy of that some place for comparison # xxx todo keys_changes = False if config_changes or keys_changes: # instead of restarting the service we call a companion script try: fetch_trigger_script_if_missing (slicename) # the trigger script actually needs to be run in the slice context of course # in addition there is a requirement to pretend we run as a login shell # hence sudo -i slice_command = [ "sudo", "-i", omf_rc_trigger_script ] to_run = tools.command_in_slice (slicename, slice_command) log_filename = "/vservers/%s/%s"%(slicename, omf_rc_trigger_log) logger.log("omf_resctl: starting %s"%to_run) logger.log("redirected into %s"%log_filename) logger.log("*not* waiting for completion..") with open(log_filename, "a") as log_file: subprocess.Popen(to_run, stdout=log_file, stderr=subprocess.STDOUT) # a first version tried to 'communicate' on that subprocess instance # but that tended to create deadlocks in some cases # causing nodemanager to stall... # we're only losing the child's retcod, no big deal except: import traceback traceback.print_exc() logger.log_exc("omf_resctl: WARNING: Could not call trigger script %s"%\ omf_rc_trigger_script, name=slicename) else: logger.log("omf_resctl: %s: omf_control'ed sliver has no change" % slicename)
def GetSlivers(data, conf=None, plc=None): if "accounts" not in data: logger.log_missing_data("omf_resctl.GetSlivers", "accounts") return try: xmpp_server = data["xmpp"]["server"] if not xmpp_server: # we have the key but no value, just as bad raise Exception except: # disabled feature - bailing out # xxx might need to clean up more deeply.. logger.log( "PLC config unsufficient (not enabled, or no server set), see the PLC_OMF category -- plugin exiting" ) return # as hrn is set only at AddNode-time, upgraded myplcs might still miss this # clue: just overwrite the hostname of all nodes # for node in GetNodes(): UpdateNode(node['node_id'],{'hostname':node['hostname']}) try: node_hrn = data["hrn"] if not node_hrn: raise Exception except: logger.log("Failed to read hrn from GetSlivers, using 'default' - *please upgrade PLCAPI*") node_hrn = "default # Failed to read hrn from GetSlivers, please upgrade PLCAPI" for sliver in data["slivers"]: name = sliver["name"] sliver_pub_key_dir = os.path.join("/home", name, ".ssh/") sliver_private_key = os.path.join(sliver_pub_key_dir, "id_rsa") for chunk in sliver["attributes"]: if chunk["tagname"] == "omf_control": # scan all versions of omf-resctl etc_path = "/vservers/%s/etc/" % name pattern = etc_path + "omf-resctl-*/omf-resctl.yaml.in" templates = glob.glob(pattern) if not templates: logger.log( "WARNING: omf_resctl plugin, no template found for slice %s using pattern %s" % (name, pattern) ) continue for template in templates: # remove the .in extension yaml = template[:-3] # figure service name as subdir under etc/ service_name = os.path.split(template.replace(etc_path, ""))[0] # read template and replace template_contents = file(template).read() yaml_contents = ( template_contents.replace("@XMPP_SERVER@", xmpp_server) .replace("@NODE_HRN@", node_hrn) .replace("@SLICE_NAME@", name) .replace("@SLIVER_PRIVATE_KEY@", sliver_private_key) .replace("@SLIVER_PUB_KEY_DIR@", sliver_pub_key_dir) ) changes = tools.replace_file_with_string(yaml, yaml_contents) logger.log("yaml_contents length=%d, changes=%r" % (len(yaml_contents), changes)) if changes: sp = subprocess.Popen( ["vserver", name, "exec", "service", service_name, "restart"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) (output, retcod) = sp.communicate() logger.log("omf_resctl: %s: restarted resource controller (retcod=%r)" % (name, retcod)) logger.log("omf_resctl: got output\n%s" % output) else: logger.log("omf_resctl: %s: omf_control'ed sliver has no change" % name)