| #!/usr/bin/env python |
| |
| import sys, os, subprocess, errno, re |
| |
| # ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ---- |
| # ---- We do this so cloud_utils can be looked up in the following order: |
| # ---- 1) Sources directory |
| # ---- 2) waf configured PYTHONDIR |
| # ---- 3) System Python path |
| for pythonpath in ( |
| "@PYTHONDIR@", |
| os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"), |
| ): |
| if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath) |
| # ---- End snippet of code ---- |
| from cloud_utils import check_selinux, CheckFailed |
| |
| E_GENERIC= 1 |
| E_NOKVM = 2 |
| E_NODEFROUTE = 3 |
| E_DHCP = 4 |
| E_NOPERSISTENTNET = 5 |
| E_VIRTRECONFIGFAILED = 7 |
| E_FWRECONFIGFAILED = 8 |
| E_AGENTRECONFIGFAILED = 9 |
| E_AGENTFAILEDTOSTART = 10 |
| E_NOFQDN = 11 |
| E_OSUNSUPP = 11 |
| E_SUDORECONFIGFAILED = 6 |
| |
| |
| def stderr(msgfmt,*args): |
| msgfmt += "\n" |
| if args: sys.stderr.write(msgfmt%args) |
| else: sys.stderr.write(msgfmt) |
| sys.stderr.flush() |
| |
| def bail(errno=E_GENERIC,message=None,*args): |
| if message: stderr(message,*args) |
| stderr("CloudStack Management Server setup aborted") |
| sys.exit(errno) |
| |
| |
| #---------------- boilerplate for python 2.4 support |
| |
| |
| # CENTOS does not have this -- we have to put this here |
| try: |
| from subprocess import check_call |
| from subprocess import CalledProcessError |
| except ImportError: |
| def check_call(*popenargs, **kwargs): |
| import subprocess |
| retcode = subprocess.call(*popenargs, **kwargs) |
| cmd = kwargs.get("args") |
| if cmd is None: cmd = popenargs[0] |
| if retcode: raise CalledProcessError(retcode, cmd) |
| return retcode |
| |
| class CalledProcessError(Exception): |
| def __init__(self, returncode, cmd): |
| self.returncode = returncode ; self.cmd = cmd |
| def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) |
| |
| # ------------ end boilerplate ------------------------- |
| |
| |
| def check_kvm(): return check_call(["kvm-ok"]) |
| def check_hostname(): return check_call(["hostname",'--fqdn']) |
| |
| class Command: |
| def __init__(self,name,parent=None): |
| self.__name = name |
| self.__parent = parent |
| def __getattr__(self,name): |
| if name == "_print": name = "print" |
| return Command(name,self) |
| def __call__(self,*args): |
| cmd = self.__get_recursive_name() + list(args) |
| #print " ",cmd |
| popen = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) |
| m = popen.communicate() |
| ret = popen.wait() |
| if ret: |
| e = CalledProcessError(ret,cmd) |
| e.stdout,e.stderr = m |
| raise e |
| class CommandOutput: |
| def __init__(self,stdout,stderr): |
| self.stdout = stdout |
| self.stderr = stderr |
| return CommandOutput(*m) |
| def __lt__(self,other): |
| cmd = self.__get_recursive_name() |
| #print " ",cmd,"<",other |
| popen = subprocess.Popen(cmd,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) |
| m = popen.communicate(other) |
| ret = popen.wait() |
| if ret: |
| e = CalledProcessError(ret,cmd) |
| e.stdout,e.stderr = m |
| raise e |
| class CommandOutput: |
| def __init__(self,stdout,stderr): |
| self.stdout = stdout |
| self.stderr = stderr |
| return CommandOutput(*m) |
| |
| def __get_recursive_name(self,sep=None): |
| m = self |
| l = [] |
| while m is not None: |
| l.append(m.__name) |
| m = m.__parent |
| l.reverse() |
| if sep: return sep.join(l) |
| else: return l |
| def __str__(self): |
| return '<Command %r>'%self.__get_recursive_name(sep=" ") |
| |
| def __repr__(self): return self.__str__() |
| |
| def checkselinux(): |
| try: |
| check_selinux() |
| except CheckFailed,e: |
| bail(E_SELINUXENABLED,"SELINUX is set to enforcing. Please set it to permissive in /etc/selinux/config. Then reboot or run setenforce permissive. Then run this program again.") |
| |
| |
| ip = Command("ip") |
| service = Command("service") |
| chkconfig = Command("chkconfig") |
| updatercd = Command("update-rc.d") |
| ufw = Command("ufw") |
| iptables = Command("iptables") |
| augtool = Command("augtool") |
| kvmok = Command("kvm-ok") |
| ifconfig = Command("ifconfig") |
| uuidgen = Command("uuidgen") |
| |
| Fedora = os.path.exists("/etc/fedora-release") |
| CentOS = os.path.exists("/etc/centos-release") or ( os.path.exists("/etc/redhat-release") and not os.path.exists("/etc/fedora-release") ) |
| |
| #--------------- procedure starts here ------------ |
| |
| stderr("Welcome to the CloudStack Management setup") |
| stderr("") |
| |
| try: |
| check_hostname() |
| stderr("The hostname of this machine is properly set up") |
| except CalledProcessError,e: |
| bail(E_NOFQDN,"This machine does not have an FQDN (fully-qualified domain name) for a hostname") |
| |
| if Fedora or CentOS: |
| checkselinux() |
| |
| try: |
| service("@PACKAGE@-management","status") |
| stderr("Stopping the CloudStack Management Server") |
| m = service("@PACKAGE@-management","stop") |
| print m.stdout + m.stderr |
| stderr("CloudStack Management Server stopped") |
| except CalledProcessError,e: |
| pass |
| |
| requiretty = augtool._print("/files/etc/sudoers/Defaults/requiretty").stdout.strip() |
| sudoeruser = augtool.match("/files/etc/sudoers/spec/user","@MSUSER@").stdout.strip() |
| |
| if requiretty: |
| sudoerstext = file("/etc/sudoers").read() |
| def restore(): |
| try: file("/etc/sudoers","w").write(sudoerstext) |
| except OSError,e: raise |
| |
| script = """rm %s |
| save"""%"/".join(requiretty.split("/")[:-1]) |
| |
| stderr("Executing the following reconfiguration script:\n%s",script) |
| |
| try: |
| returned = augtool < script |
| if "Saved 1 file" not in returned.stdout: |
| print returned.stdout + returned.stderr |
| restore() |
| bail(E_SUDORECONFIGFAILED,"sudoers reconfiguration failed.") |
| else: |
| stderr("sudoers reconfiguration complete") |
| except CalledProcessError,e: |
| restore() |
| print e.stdout + e.stderr |
| bail(E_SUDORECONFIGFAILED,"sudoers reconfiguration failed") |
| |
| if "@MSUSER@" not in sudoeruser: |
| sudoerstext = file("/etc/sudoers").read() |
| def restore(): |
| try: file("/etc/sudoers","w").write(sudoerstext) |
| except OSError,e: raise |
| |
| script = """ins spec after /files/etc/sudoers/spec[last()] |
| set /files/etc/sudoers/spec[last()]/user @MSUSER@ |
| set /files/etc/sudoers/spec[last()]/host_group/host ALL |
| set /files/etc/sudoers/spec[last()]/host_group/command ALL |
| set /files/etc/sudoers/spec[last()]/host_group/command/tag NOPASSWD |
| save""" |
| |
| stderr("Executing the following reconfiguration script:\n%s",script) |
| |
| try: |
| returned = augtool < script |
| if "Saved 1 file" not in returned.stdout: |
| print returned.stdout + returned.stderr |
| restore() |
| bail(E_SUDORECONFIGFAILED,"sudoers reconfiguration failed.") |
| else: |
| stderr("sudoers reconfiguration complete") |
| except CalledProcessError,e: |
| restore() |
| print e.stdout + e.stderr |
| bail(E_SUDORECONFIGFAILED,"sudoers reconfiguration failed") |
| |
| ports = "80 8080 8096 8250 9090".split() |
| if Fedora or CentOS: |
| try: |
| o = chkconfig("--list","iptables") |
| iptableschkconfig = True |
| except CalledProcessError,e: |
| stderr("No need to set up iptables as the service is not registered in the SysV init system") |
| iptableschkconfig = False |
| if iptableschkconfig is True: |
| try: |
| o = chkconfig("--list","iptables") |
| if ":on" in o.stdout and os.path.exists("/etc/sysconfig/iptables"): |
| stderr("Setting up firewall rules to permit traffic to CloudStack services") |
| service.iptables.start() ; print o.stdout + o.stderr |
| for p in ports: iptables("-I","INPUT","1","-p","tcp","--dport",p,"-j","ACCEPT") |
| o = service.iptables.save() ; print o.stdout + o.stderr |
| else: |
| stderr("No need to set up iptables as the service is unconfigured or not set to start up at boot") |
| except CalledProcessError,e: |
| print e.stdout+e.stderr |
| bail(E_FWRECONFIGFAILED,"Firewall rules could not be set") |
| else: |
| stderr("Setting up firewall rules to permit traffic to CloudStack services") |
| try: |
| for p in ports: ufw.allow(p) |
| stderr("Rules set") |
| except CalledProcessError,e: |
| print e.stdout+e.stderr |
| bail(E_FWRECONFIGFAILED,"Firewall rules could not be set") |
| |
| stderr("We are going to enable ufw now. This may disrupt network connectivity and service availability. See the ufw documentation for information on how to manage ufw firewall policies.") |
| try: |
| o = ufw.enable < "y\n" ; print o.stdout + o.stderr |
| except CalledProcessError,e: |
| print e.stdout+e.stderr |
| bail(E_FWRECONFIGFAILED,"Firewall could not be enabled") |
| |
| stderr("") |
| stderr("CloudStack Management Server setup completed successfully") |
| |
| try: |
| if Fedora or CentOS: chkconfig("tomcat6","off") |
| else: updatercd("tomcat6","disable") |
| service("tomcat6","status") |
| stderr("Stopping Tomcat") |
| m = service("tomcat6","stop") |
| print m.stdout + m.stderr |
| stderr("Tomcat stopped") |
| except CalledProcessError,e: |
| pass |
| |
| try: |
| if Fedora or CentOS: |
| chkconfig("--level","35","network","on") |
| except CalledProcessError,e: |
| pass |
| |
| stderr("Starting the CloudStack Management Server") |
| try: |
| m = service("@PACKAGE@-management","start") |
| print m.stdout + m.stderr |
| except CalledProcessError,e: |
| print e.stdout + e.stderr |
| bail(E_AGENTFAILEDTOSTART,"@PACKAGE@-management failed to start") |
| |
| |
| # FIXMES: 1) nullify networkmanager on ubuntu (asking the user first) and enable the networking service permanently |