#-*- coding: utf-8 -*- # Copyright 2010 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import re import sys from cl_install import cl_install, InstallError, __app__, __version__,\ get_install_errors from cl_vars_share import varsShare from cl_opt import opt from cl_share_cmd import share_cmd from utils import ip as iputils from cl_utils import isPkgInstalled from cl_lang import lang lang().setLanguage(sys.modules[__name__]) OSSYSTEM_LIST=sorted(varsShare.dictNameSystem.keys()) NM_LIST=sorted(varsShare.dictNetworkManagers.keys()) DESCRIPTION = _("Calculate Linux installation and configuration utility") CMD_OPTIONS = [{'shortOption':"d", 'longOption':"disk", 'optVal':"DISK[:[DIR:FILESYSTEM:OPTIONS]]", 'action':'append', 'help':_("DISK for installation, will be mounted to DIR") + ". " + _("DIR set to 'none' will cancel the mount point transfer") + ". " +_("For creating bind mount point you have to specify" " the source directory as DISK") }, {'shortOption':"w", 'longOption':"swap", 'optVal':"SWAP_DISK", 'action':'append', 'help':_("swap disk for installation") }, {'longOption':"mbr", 'optVal':"DEVICE", 'help':_("boot disk for the system bound for install " "(for recording MBR), off - disable MBR writing") }, {'longOption':"type", 'optVal':"DISKTYPE", 'type':'choice', 'choices':['flash','hdd','usb-hdd'], 'help':_("device type for the system bound for install") }, {'longOption':'iso', 'optVal':"ISO", 'help':_("ISO image for installation")}, {'shortOption':"s", 'longOption':"os", 'optVal':"SYSTEM", 'type':'choice', 'choices_regignore': OSSYSTEM_LIST, 'help':_("select the operation system") }, {'longOption':"march", 'optVal':"ARCH", 'type':'choice', 'choices':['i686','x86_64','auto'], 'help':_("select the processor architecture")+ \ _("{0} or {1}").format(" (i686,x86_64","auto)") }, {'longOption':"build", 'help':_("installation for assemble") }, {'shortOption':"l", 'longOption':"lang", 'optVal':"LANG", 'help':_("set the language") }, {'shortOption':"u", 'longOption':"user", 'optVal':"USER", 'action':'append', 'help':_("add a user to the installed system") }, {'shortOption':"A", 'longOption':"autologin", 'optVal':"USER", 'help':_("add an autologin user to the installed system") }, {'longOption':"hostname", 'optVal':"HOSTNAME", 'help':_("set the short hostname of the full hostname") }, {'longOption':"netconf", 'optVal':"NETMANAGER", 'type':'choice', 'choices_regignore': NM_LIST, 'help':_("network manager (%s)")% _("{0} or {1}").format(",".join(NM_LIST[0:-1]), NM_LIST[-1])}, {'longOption':"dhcp", 'optVal':"IFACE", 'action':'append', 'help':_("get the ip address by %s for " "the specified interface")%"DHCP" }, {'longOption':"ip", 'optVal':"[IFACE:]IP", 'action':'append', 'help':_("ip address with net (example:%s)")%"192.168.1.1/24" }, {'longOption':"route", 'optVal':"NETWORK:[GATEWAY][:DEV[:SOURCE]]", 'action':'append', 'help':_("add a routing rule") }, {'longOption':"dns", 'optVal':"DNS", 'help':_("domain name servers (comma-separated)") }, {'longOption':"proxy", 'optVal':"PROXY", 'help':_("set the proxy server for the system") }, {'longOption':"ntp", 'optVal':"NTP", 'help':_("set the ntp server for the system") }, {'longOption':"video", 'optVal':"VIDEODRV", 'help':_("set the video driver") }, {'shortOption':"X", 'optVal':"x", 'help':_("set Xorg resolution") }, {'longOption':"fb", 'optVal':"x", 'help':_("set frame buffer resolution") }, {'longOption':"scheduler", 'optVal':"SCHEDULER", 'help':_("set I/O scheduler") }, {'longOption':"timezone", 'optVal':"TIMEZONE", 'help':_("set the timezone") }, {'longOption':"nouuid", 'help':_("do not use UUID") }, {'longOption':'set'}, {'shortOption':"U", 'longOption':"update", 'help':_("install newer images only")}, {'shortOption':"f", 'longOption':"force", 'help':_("no questions during installation") }, {'longOption':"startup", 'help':_("configuring the current system") }, {'longOption':"live", 'help':_("configure only mutable parameters, " "used in conjunction with the option '--startup'") }, {'longOption':"install", 'help':_("install the package") }, {'longOption':"uninstall", 'help':_("uninstall the package") }, {'longOption':"nospinner", 'help':_("disable the spinner") }, {'shortOption':"P", 'help':_("use passwords for the users accounts " "(from standard input)") }, {'shortOption':'p', 'longOption':"show-partitions", 'help':_("display all partitions")} ] class OptException(Exception): pass class install_cmd(share_cmd): """Class for work with cl_install by console""" def __init__(self): setpos = \ filter(lambda x:x[1].get('longOption')=="set", enumerate(CMD_OPTIONS))[0][0] CMD_OPTIONS[setpos] = opt.variable_set[0] self.optobj = opt(package=__app__, version=__version__, description=DESCRIPTION, option_list= CMD_OPTIONS + opt.variable_view + opt.color_control, check_values=self.checkOpts) self.logicObj = cl_install() # names incompatible options with --startup self.optionsStartupIncompatible = ["type","d", "b", "mbr", "w", "f","U", "s","install","uninstall","build","u"] self.optionsDhcpIncompatible = ["ip","gateway","dns"] self.errorWithExample = \ _("option {optname}: {errormess}:" " '{value}' (example: '{example}')") def _getNamesAllSetOptions(self): """Get list set options""" setOptDict = self.optobj.values.__dict__.items() defaultOptDict = self.optobj.get_default_values().__dict__.items() return reduce(lambda x,y: x+[y[0][0]], filter(lambda x:x[0][1] != x[1][1], zip(setOptDict,defaultOptDict)), []) def getStringIncompatibleOptions(self,listOpt): """Форматированная строка несовместимых опций разделенных ','""" return ", ".join(map(lambda x: len(x) == 1 and "'-%s'"%x or "'--%s'"%x, listOpt)) def checkIncompatibleStartup(self): """Check incompatible options for option --startup""" incompatible = list(set(self._getNamesAllSetOptions()) & set(self.optionsStartupIncompatible)) if incompatible: self.optobj.error(_("incompatible options")+":"+" %s"\ %self.getStringIncompatibleOptions(incompatible+["startup"])) def checkIncompatibleDhcp(self): """Check incompatible options for option --dchp""" incompatible = list(set(self._getNamesAllSetOptions()) & set(self.optionsDhcpIncompatible)) if incompatible: self.optobj.error(_("incompatible options")+":"+" %s"\ %self.getStringIncompatibleOptions(incompatible+["dhcp"])) def checkIncompatibleInstallUninstall(self): """Check incompatible options for options --install and --uninstall""" opts = self._getNamesAllSetOptions() if len(opts)>1: self.optobj.error(_("incompatible options")+":"+" %s"\ %self.getStringIncompatibleOptions(opts)) def __checkByReg(self,reg="",value="",valueopt="",valuename="",example=""): """Check option specifed by value""" if value: if not re.match(reg,value): self.optobj.error(self.errorWithExample.format( optname=valueopt, errormess=_("%s specifing error")%valuename, value=value, example=example)) def checkOpts(self, values, args): """Check values all specified options.""" if len(args) > 0: self.optobj.error(_("unrecognized option") + ": %s"% "".join(args)) if not values.startup: if values.live: errMsg = _("incorrect option") + ":" + " %s" %"--live" +\ ": " + _("used with option '--startup'") self.optobj.error(errMsg) if values.install or values.uninstall: self.checkIncompatibleInstallUninstall() if values.startup: self.checkIncompatibleStartup() if values.dhcp: self.checkIncompatibleDhcp() if values.A == "root": self.optobj.error(_("The autologin user cannot be root")) if not values.v: if values.filter: errMsg = _("incorrect option") + ":" + " %s" %"--filter" +\ ": " + _("use with option '-v'") self.optobj.error(errMsg) if values.xml: errMsg = _("incorrect option") + ":" + " %s" %"--xml" +\ ": " + _("use with option '-v'") self.optobj.error(errMsg) self.__checkByReg(reg="^\d+x\d+$",value=values.X,valueopt="-X", valuename=_("X resolution"),example="1024x768") self.__checkByReg(reg="^\d+x\d+$",value=values.fb,valueopt="--fb", valuename=_("frame buffer resolution"), example="1024x768") if values.ip: for ipaddr in values.ip: if not re.match("^(\w+:)?%s$"%iputils.IP_ADDR_NET,ipaddr): self.optobj.error(self.errorWithExample.format( optname="--ip", errormess=_("%s specifing error")%"ip", value=ipaddr, example="eth0:192.168.0.21/16")) if not values.dns is None: if not re.match("(^{0}(,{0})*|)$".format(iputils.IP_ADDR), values.dns): self.optobj.error(self.errorWithExample.format( optname="--dns", errormess=_("%s specifing error")%"dns", value=values.dns, example="8.8.8.8")) if values.route: for route in values.route: if not re.match("^({net}|default):(({ipaddr})?" "(:\w+(:{ipaddr})?)?)?$".format( net=iputils.IP_ADDR_NET,ipaddr=iputils.IP_ADDR),route): self.optobj.error(self.errorWithExample.format( optname="--route", errormess=_("%s specifing error")%_("route"), value=route, example="default:192.168.1.1")) # if system installation if values.scheduler: if not values.scheduler in \ self.logicObj.clVars.Get('os_kernel_schedulers'): self.optobj.error(self.errorWithExample.format( optname="--scheduler", errormess=_("%s specifing error")%"scheduler", value=values.scheduler, example="deadline")) else: self.logicObj.clVars.Set('os_install_kernel_scheduler', values.scheduler,force=True) if not (values.install or values.uninstall or values.startup or values.live): if values.v is False and \ not values.p and \ values.d is None and \ not self.logicObj.clVars.Get('os_install_dev_from'): self.optobj.error(_("need specify disk by '-d' option")) # check syntax DISK:DIR:FS:'Do I need to format the disk' if values.d: reTrueDisk = re.compile("^[^:]+(:[^:]*){0,3}$") wrongValue = filter(lambda x: not reTrueDisk.match(x),values.d) if wrongValue: self.optobj.error(self.errorWithExample.format( optname="-d", errormess=_("%s specifing error")%_("disk"), value=", ".join(wrongValue), example="/dev/sda2:/:ext4")) # check syntax SWAP_DISK if values.w: reTrueBind = re.compile("^[^:]+$") wrongValue = filter(lambda x: not reTrueBind.match(x),values.w) if wrongValue: self.optobj.error(self.errorWithExample.format( optname="-w", errormess=_("%s specifing error")%_("disk"), value=", ".join(wrongValue), example="/dev/sda1")) #check boot device if values.mbr: bootDisk = values.mbr reBootDisk = re.compile("^/dev/.+[^\d]|off$") if not reBootDisk.match(bootDisk): self.optobj.error(_("option %s:") %"mbr" + " " +\ _("disk specifing error: '%s'")%bootDisk) # check syntax --set self.optobj.checkVarSyntax(values) return (values, args) def setLang(self,lang): """Process set locales by lang""" if self.logicObj.setAllLocaleByLang(lang): return True else: self.printERROR(_("specified language %s is unsupported")%lang) return False def setProxyNtpHostname(self,proxy,ntp,hostname): """Process set locales by lang""" getVar = self.logicObj.clVars.Get setVar = self.logicObj.clVars.Set setWriteVar = self.logicObj.clVars.SetWriteVar if proxy: if not setWriteVar('os_install_proxy',proxy): self.printERROR(get_install_errors(),printBR=False) return False if ntp: if not setWriteVar('os_install_ntp',ntp): self.printERROR(get_install_errors(),printBR=False) return False if hostname: if "." in hostname: hostname, op, domain = hostname.partition('.') setVar('os_install_net_hostname', hostname,True) setVar('os_install_net_domain', domain,True) dns_search = getVar("os_install_net_dns_search") if not domain in dns_search: setVar("os_install_net_dns_search",domain,True) else: setVar('os_install_net_hostname', hostname,True) return True def setNetworkParams(self,ipaddrs,routes,dns,setup,dhcps): """Set nework params""" if not dns is None: self.logicObj.clVars.Set("os_install_net_dns", dns.replace(',',' '), True) ipaddrs = map(lambda x:x.split(":"),ipaddrs or []) routes = map(lambda x:x+[""]*(4-len(x)), map(lambda x:x.split(":"),routes or [])) dhcps = dhcps or [] if not self.logicObj.setNetwork(ipaddrs,dhcps,routes): return False if setup: if not isPkgInstalled(setup): self.printERROR(_("Network manager %s is not installed")%setup) return False self.logicObj.clVars.Set("os_install_net_conf",setup,True) return True def setVars(self,options): """Process setting values for variables""" values = self.optobj.values if values.video: if not self.logicObj.setVideo(values.video, startup=values.startup): return False if values.X: if not self.clVars.Set('os_install_x11_resolution', values.X, force=True): return False if values.fb: if not self.clVars.Set('os_install_fb_resolution', "%s-32"%values.fb, force=True): return False if values.timezone: if not self.logicObj.setTimezone(values.timezone): return False if options.set: for vals in options.set: for val in vals.split(','): k,o,v = val.partition('=') if self.logicObj.clVars.exists(k): if self.logicObj.clVars.SetWriteVar(k,v) == False: self.printERROR(get_install_errors(),printBR=False) return False else: self.printERROR(_('variable %s not found')%k) return False return True def setAction(self,startup,live): """Set action by configuration or install system""" if live: self.logicObj.clVars.Set('cl_action',"live",True) elif startup: self.logicObj.clVars.Set('cl_action',"merge",True) else: self.logicObj.clVars.Set('cl_action',"system",True) def checkAndSetInstallOptions(self,diskOptions, swapOptions, usersOptions, autologinOptions): """Check and set disk, swap and bind cmd options""" if self.optobj.values.s: self.logicObj.setLinuxName(self.optobj.values.s.upper()) if self.optobj.values.march: self.logicObj.setArchitecture(self.optobj.values.march) if self.optobj.values.nouuid: self.logicObj.clVars.Set('cl_uuid_set','off',True) if self.optobj.values.build: self.logicObj.clVars.Set('os_install_scratch',"on",True) else: self.logicObj.clVars.Set('os_install_scratch',"off",True) if self.optobj.values.type: self.logicObj.clVars.Set('os_install_root_type', self.optobj.values.type, True) if self.optobj.values.iso: if not self.logicObj.setIso(self.optobj.values.iso): return False listDiskOptions = [] listBindOptions = [] listSwapOptions = [] if diskOptions: listDiskOptions = self._parseOptDisk(diskOptions) if listDiskOptions is False: return False listBindOptions = self._parseOptBind(diskOptions) if listBindOptions is False: return False if swapOptions: listSwapOptions = self._parseOptSwap(swapOptions) if listSwapOptions is False: return False if not self.logicObj.setInstallOptions(listDiskOptions, listBindOptions, listSwapOptions, usersOptions, autologinOptions, self.optobj.values.mbr): return False return True def _parseOptSwap(self, listOpt): """Parse value cmd option --swap""" listNameOptions = ["dev"] lenOptions = len(listNameOptions) itemOptions = map(lambda x: (x,''), listNameOptions) rawListOpt = map(lambda x: filter(lambda y: y, x.split(':')), listOpt) sameLenListOpt = [] for listData in rawListOpt: lenListData = len(listData) if lenListData>1: errOpt = ":".join(filter(lambda x: x, listData)) self.printERROR(_("incorrect '%s'")%errOpt) return False dictOpt = {} dictOpt.update(zip(map(lambda x:x[0],itemOptions),listData)) sameLenListOpt.append(dictOpt) return sameLenListOpt def _parseOptBind(self, listOpt): """Parse value cmd option --bind""" listOpt = filter(lambda x:not x.startswith('/dev/'),listOpt) listNameOptions = ["srcMountPoint", "destMountPoint"] lenOptions = len(listNameOptions) itemOptions = map(lambda x: (x,''), listNameOptions) rawListOpt = map(lambda x: filter(lambda y: y, x.split(':')), listOpt) sameLenListOpt = [] for listData in rawListOpt: lenListData = len(listData) if lenListData < lenOptions: listData += ['']*(lenOptions-lenListData) dictOpt = {} dictOpt.update(zip(map(lambda x: x[0], itemOptions),listData)) srcDir = dictOpt["srcMountPoint"] destDir = dictOpt["destMountPoint"] if not (srcDir and destDir): errOpt = ":".join(filter(lambda x: x, listData)) self.printERROR(_("incorrect '%s'")%errOpt) return False sameLenListOpt.append(dictOpt) return sameLenListOpt def _parseOptDisk(self, listOpt): """Parse value cmd option --disk""" listOpt = filter(lambda x:x.startswith('/dev/'),listOpt) listNameOptions = ["dev","mountPoint","fileSystem","options"] lenOptions = len(listNameOptions) itemOptions = map(lambda x: (x,''), listNameOptions) rawListOpt = map(lambda x: x.split(':'), listOpt) sameLenListOpt = [] for listData in rawListOpt: lenListData = len(listData) if lenListData < lenOptions: listData += ['']*(lenOptions-lenListData) dictOpt = {} dictOpt.update(zip(map(lambda x: x[0],itemOptions), listData)) options = [] strOptions = dictOpt["options"] if strOptions: options = filter(lambda x: x, strOptions.split(',')) dictOpt["options"] = options sameLenListOpt.append(dictOpt) return sameLenListOpt def templateSelect(self,template): """Process template appling""" if self.logicObj.applyTemplatesForSystem(): return True else: return False def installSystem(self, force=False, bootDisk=None, users=[], stdinReadPwd=False, builder=False, flagSpinner=True, update=False): """Run install system""" if self.logicObj.installSystem(force=force, bootDisk=bootDisk, stdinReadPwd=stdinReadPwd, builder=builder, flagSpinner=flagSpinner,update=update): if self.logicObj.clVars.Get('os_install_root_type') != "flash": self.defaultPrint("\n") self.defaultPrint(_("To apply the changes you have to reboot")+ ".\n") return True else: return False def showPartitions(self): self.logicObj.printAllPartitonsTable() def configureSystem(self,autologin): """Run configure system""" if self.logicObj.configureSystem(autologin): return True else: return False def installPackage(self): """Run package installation""" if self.logicObj.installPackage(): return True else: return False def uninstallPackage(self): """Run package uninstallation""" if self.logicObj.uninstallPackage(): return True else: return False