+ filedir = os.path.dirname(filename)
+ # dirname does not return "." for a local filename like its shell counterpart
+ if filedir:
+ if not os.path.exists(filedir):
+ try:
+ os.makedirs(filedir, 0o777)
+ except:
+ raise PLCPermissionDenied("Could not create dir {}".format(filedir))
+
+ return filename
+
+ def build_command(self, nodename, node_type, build_sh_spec, node_image, type, floppy_file):
+ """
+ returns a tuple
+ (*) build command to be run
+ (*) location of the log_file
+ """
+
+ command = ""
+
+ # regular node, make build's arguments
+ # and build the full command line to be called
+ if node_type not in [ 'regular', 'reservable' ]:
+ logger.error("GetBootMedium.build_command: unexpected node_type {}".format(node_type))
+ return command, None
+
+ build_sh_options = ""
+ if "cramfs" in build_sh_spec:
+ type += "_cramfs"
+ if "serial" in build_sh_spec:
+ build_sh_options += " -s {}".format(build_sh_spec['serial'])
+ if "variant" in build_sh_spec:
+ build_sh_options += " -V {}".format(build_sh_spec['variant'])
+
+ for karg in build_sh_spec['kargs']:
+ build_sh_options += ' -k "{}"'.format(karg)
+
+ import time
+ date = time.strftime('%Y-%m-%d-%H-%M', time.gmtime())
+ if not os.path.isdir(self.LOGDIR):
+ os.makedirs(self.LOGDIR)
+ log_file = "{}/{}-{}.log".format(self.LOGDIR, date, nodename)
+
+ command = '{} -f "{}" -o "{}" -t "{}" {} > {} 2>&1'\
+ .format(self.BOOTCDBUILD,
+ floppy_file,
+ node_image,
+ type,
+ build_sh_options,
+ log_file)
+
+ logger.info("The build command line is {}".format(command))
+
+ return command, log_file
+
+ def call(self, auth, node_id_or_hostname, action, filename, options=None):
+
+ if options is None:
+ options = []
+
+ self.trash = []
+
+ ### compute file suffix and type
+ if action.find("-iso") >= 0 :
+ suffix = ".iso"
+ type = "iso"
+ elif action.find("-usb") >= 0:
+ suffix = ".usb"
+ type = "usb"
+ else:
+ suffix = ".txt"
+ type = "txt"
+
+ # check for node existence and get node_type
+ nodes = Nodes(self.api, [node_id_or_hostname])
+ if not nodes:
+ raise PLCInvalidArgument("No such node {}".format(node_id_or_hostname))
+ node = nodes[0]
+
+ logger.info("GetBootMedium: {} requested on node {}. Node type is: {}"
+ .format(action, node['node_id'], node['node_type']))
+
+ # check the required action against the node type
+ node_type = node['node_type']
+ if action not in allowed_actions[node_type]:
+ raise PLCInvalidArgument(
+ "Action {} not valid for {} nodes, valid actions are {}"
+ .format(action, node_type, "|".join(allowed_actions[node_type])))
+
+ # handle / canonicalize options
+ if type == "txt":
+ if options:
+ raise PLCInvalidArgument("Options are not supported for node configs")
+ else:
+ # create a dict for build.sh
+ build_sh_spec = {'kargs':[]}
+ # use node tags as defaults
+ # check for node tag equivalents
+ tags = NodeTags(
+ self.api,
+ {'node_id': node['node_id'],
+ 'tagname': ['serial', 'cramfs', 'kvariant', 'kargs',
+ 'no-hangcheck', 'systemd-console', 'systemd-debug', ]},
+ ['tagname', 'value'])
+ if tags:
+ for tag in tags:
+ if tag['tagname'] == 'serial':
+ build_sh_spec['serial'] = tag['value']
+ elif tag['tagname'] == 'cramfs':
+ build_sh_spec['cramfs'] = True
+ elif tag['tagname'] == 'kvariant':
+ build_sh_spec['variant'] = tag['value']
+ elif tag['tagname'] == 'kargs':
+ build_sh_spec['kargs'] += tag['value'].split()
+ elif tag['tagname'] == 'no-hangcheck':
+ build_sh_spec['kargs'].append('hcheck_reboot0')
+ elif tag['tagname'] == 'systemd-console':
+ build_sh_spec['kargs'].append('systemd.log_target=console')
+ build_sh_spec['kargs'].append(
+ 'systemd.default_standard_output=journal+console')
+ build_sh_spec['kargs'].append(
+ 'systemd.default_standard_error=journal+console')
+ elif tag['tagname'] == 'systemd-debug':
+ build_sh_spec['kargs'].append('systemd.log_level=debug')
+ # then options can override tags
+ for option in options:
+ if option == "cramfs":
+ build_sh_spec['cramfs'] = True
+ elif option == 'partition':
+ if type != "usb":
+ raise PLCInvalidArgument("option 'partition' is for USB images only")
+ else:
+ type = "usb_partition"
+ elif option == "serial":
+ build_sh_spec['serial'] = 'default'
+ elif option.find("serial:") == 0:
+ build_sh_spec['serial'] = option.replace("serial:", "")
+ elif option.find("variant:") == 0:
+ build_sh_spec['variant'] = option.replace("variant:", "")
+ elif option == "no-hangcheck":
+ build_sh_spec['kargs'].append('hcheck_reboot0')
+ elif option == "systemd-console":
+ build_sh_spec['kargs'].append('systemd.log_target=console')
+ build_sh_spec['kargs'].append(
+ 'systemd.default_standard_output=journal+console')
+ build_sh_spec['kargs'].append(
+ 'systemd.default_standard_error=journal+console')
+ elif option == "systemd-debug":
+ build_sh_spec['kargs'].append('systemd.log_level=debug')
+ else:
+ raise PLCInvalidArgument("unknown option {}".format(option))
+
+ # compute nodename according the action
+ if action.find("node-") == 0:
+ nodename = node['hostname']
+ else:
+ node = None
+ # compute a 8 bytes random number
+ tempbytes = random.sample(range(0, 256), 8);
+ def hexa2(c):
+ return chr((c>>4)+65) + chr((c&16)+65)
+ nodename = "".join(map(hexa2, tempbytes))
+
+ # get nodefamily
+ pldistro, fcdistro, arch = self.get_nodefamily(node, auth)
+ self.nodefamily = "{}-{}-{}".format(pldistro, fcdistro, arch)
+
+ # apply on globals
+ for attr in ["BOOTCDDIR", "BOOTCDBUILD", "GENERICDIR"]:
+ setattr(self, attr,
+ getattr(self, attr).replace("@NODEFAMILY@", self.nodefamily))
+
+ filename = self.handle_filename(filename, nodename, suffix, arch)
+
+ # log call
+ if node:
+ self.message = 'GetBootMedium on node {} - action={}'.format(nodename, action)
+ self.event_objects = {'Node': [node ['node_id']]}
+ else:
+ self.message = 'GetBootMedium - generic - action={}'.format(action)