3 # Copyright (C) 2010-2013 CEA/DEN
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 parser = src.options.Options()
30 parser.add_option('n', 'name', 'string', 'name', _('Optional: The name of the'
31 ' launcher (default is '
32 'APPLICATION.profile.launcher_name)'))
33 parser.add_option('c', 'catalog', 'string', 'catalog',
34 _('Optional: The resources catalog to use'))
35 parser.add_option('', 'gencat', 'string', 'gencat',
36 _("Optional: Create a resources catalog for the specified machines "
37 "(separated with ',') \n\tNOTICE: this command will ssh to retrieve"
38 " information to each machine in the list"))
40 def generate_launch_file(config,
46 '''Generates the launcher file.
48 :param config Config: The global configuration
49 :param logger Logger: The logger instance to use for the display
51 :param launcher_name str: The name of the launcher to generate
52 :param pathlauncher str: The path to the launcher to generate
53 :param display boolean: If False, do not print anything in the terminal
54 :param additional_env dict: The dict giving additional
56 :return: The launcher file path.
60 # Compute the default launcher path if it is not provided in pathlauncher
62 filepath = os.path.join(pathlauncher, launcher_name)
64 # Remove the file if it exists in order to replace it
65 if os.path.exists(filepath):
68 # Add the APPLI variable
69 additional_env['APPLI'] = filepath
72 # get KERNEL bin installation path
73 # (in order for the launcher to get python salomeContext API)
74 kernel_cfg = src.product.get_product_config(config, "KERNEL")
75 if not src.product.check_installation(kernel_cfg):
76 raise src.SatException(_("KERNEL is not installed"))
77 kernel_root_dir = kernel_cfg.install_dir
79 # set kernel bin dir (considering fhs property)
80 if src.get_property_in_product_cfg(kernel_cfg, "fhs"):
81 bin_kernel_install_dir = os.path.join(kernel_root_dir,"bin")
83 bin_kernel_install_dir = os.path.join(kernel_root_dir,"bin","salome")
85 # Get the launcher template
86 withProfile = src.fileEnviron.withProfile\
87 .replace("BIN_KERNEL_INSTALL_DIR", bin_kernel_install_dir)\
88 .replace("KERNEL_INSTALL_DIR", kernel_root_dir)
90 before, after = withProfile.split(
91 "# here your local standalone environment\n")
93 # create an environment file writer
94 writer = src.environment.FileEnvWriter(config,
100 # Display some information
102 # Write the launcher file
103 logger.write(_("Generating launcher for %s :\n") %
104 src.printcolors.printcLabel(config.VARS.application), 1)
105 logger.write(" %s\n" % src.printcolors.printcLabel(filepath), 1)
107 # open the file and write into it
108 launch_file = open(filepath, "w")
109 launch_file.write(before)
111 writer.write_cfgForPy_file(launch_file, additional_env=additional_env)
112 launch_file.write(after)
115 # change the rights in order to make the file executable for everybody
127 def generate_catalog(machines, config, logger):
128 """Generates an xml catalog file from a list of machines.
130 :param machines List: The list of machines to add in the catalog
131 :param config Config: The global configuration
132 :param logger Logger: The logger instance to use for the display
134 :return: The catalog file path.
137 # remove empty machines
138 machines = map(lambda l: l.strip(), machines)
139 machines = filter(lambda l: len(l) > 0, machines)
142 src.printcolors.print_value(logger, _("Generate Resources Catalog"),
143 ", ".join(machines), 4)
145 # The command to execute on each machine in order to get some information
146 cmd = '"cat /proc/cpuinfo | grep MHz ; cat /proc/meminfo | grep MemTotal"'
147 user = getpass.getuser()
149 # Create the catalog path
150 catfile = src.get_tmp_filename(config, "CatalogResources.xml")
151 catalog = file(catfile, "w")
154 catalog.write("<!DOCTYPE ResourcesCatalog>\n<resources>\n")
156 logger.write(" ssh %s " % (k + " ").ljust(20, '.'), 4)
159 # Verify that the machine is accessible
160 ssh_cmd = 'ssh -o "StrictHostKeyChecking no" %s %s' % (k, cmd)
161 p = subprocess.Popen(ssh_cmd, shell=True,
162 stdin=subprocess.PIPE,
163 stdout=subprocess.PIPE,
164 stderr=subprocess.PIPE)
167 if p.returncode != 0: # The machine is not accessible
168 logger.write(src.printcolors.printc(src.KO_STATUS) + "\n", 4)
170 src.printcolors.printcWarning(p.stderr.read()), 2)
172 # The machine is accessible, write the corresponding section on
174 logger.write(src.printcolors.printc(src.OK_STATUS) + "\n", 4)
175 lines = p.stdout.readlines()
176 freq = lines[0][:-1].split(':')[-1].split('.')[0].strip()
177 nb_proc = len(lines) -1
178 memory = lines[-1].split(':')[-1].split()[0].strip()
179 memory = int(memory) / 1000
181 catalog.write(" <machine\n")
182 catalog.write(" protocol=\"ssh\"\n")
183 catalog.write(" nbOfNodes=\"1\"\n")
184 catalog.write(" mode=\"interactif\"\n")
185 catalog.write(" OS=\"LINUX\"\n")
186 catalog.write(" CPUFreqMHz=\"%s\"\n" % freq)
187 catalog.write(" nbOfProcPerNode=\"%s\"\n" % nb_proc)
188 catalog.write(" memInMB=\"%s\"\n" % memory)
189 catalog.write(" userName=\"%s\"\n" % user)
190 catalog.write(" name=\"%s\"\n" % k)
191 catalog.write(" hostname=\"%s\"\n" % k)
192 catalog.write(" >\n")
193 catalog.write(" </machine>\n")
195 catalog.write("</resources>\n")
199 def copy_catalog(config, catalog_path):
200 """Copy the xml catalog file into the right location
202 :param config Config: The global configuration
203 :param catalog_path str: the catalog file path
204 :return: The environment dictionary corresponding to the file path.
207 # Verify the existence of the file
208 if not os.path.exists(catalog_path):
209 raise IOError(_("Catalog not found: %s") % catalog_path)
210 # Get the application directory and copy catalog inside
211 out_dir = config.APPLICATION.workdir
212 new_catalog_path = os.path.join(out_dir, "CatalogResources.xml")
214 shutil.copy(catalog_path, new_catalog_path)
215 additional_environ = {'USER_CATALOG_RESOURCES_FILE' : new_catalog_path}
216 return additional_environ
220 ##################################################
223 # Describes the command
225 return _("The launcher command generates a SALOME launcher.\n\nexample:"
226 "\nsat launcher SALOME-master")
230 def run(args, runner, logger):
233 (options, args) = parser.parse_args(args)
235 # Verify that the command was called with an application
236 src.check_config_has_application( runner.cfg )
238 # Determine the launcher name (from option, profile section or by default "salome")
240 launcher_name = options.name
242 launcher_name = src.get_launcher_name(runner.cfg)
244 # set the launcher path
245 launcher_path = runner.cfg.APPLICATION.workdir
247 # Copy a catalog if the option is called
248 additional_environ = {}
250 additional_environ = copy_catalog(runner.cfg, options.catalog)
252 # Generate a catalog of resources if the corresponding option was called
254 catalog_path = generate_catalog(options.gencat.split(","),
257 additional_environ = copy_catalog(runner.cfg, catalog_path)
259 # Generate the launcher
260 launcherPath = generate_launch_file( runner.cfg,
264 additional_env = additional_environ )