def _apply_userdata_restart_httpd(self, to): conf_folder = os.path.join(self.USERDATA_ROOT, to.namespaceName) conf_path = os.path.join(conf_folder, 'lighttpd.conf') pid = linux.find_process_by_cmdline([conf_path]) if not pid: shell.call('ip netns exec %s lighttpd -f %s' % (to.namespaceName, conf_path)) def check(_): pid = linux.find_process_by_cmdline([conf_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('lighttpd[conf-file:%s] is not running after being started %s seconds' % (conf_path, 5))
def _refresh_dnsmasq(self, ns_name, conf_file_path): pid = linux.find_process_by_cmdline([conf_file_path]) if not pid: self._restart_dnsmasq(ns_name, conf_file_path) return if self.signal_count > 50: self._restart_dnsmasq(ns_name, conf_file_path) self.signal_count = 0 return shell.call('kill -1 %s' % pid) self.signal_count += 1
def _kill_lb(self, to): pid_file_path = self._make_pid_file_path(to.lbUuid, to.listenerUuid) pid = linux.find_process_by_cmdline([pid_file_path]) if pid: shell.call('kill %s' % pid) linux.rm_file_force(pid_file_path) linux.rm_file_force(self._make_conf_file_path(to.lbUuid, to.listenerUuid)) ipt = iptables.from_iptables_save() ipt.delete_chain(self._make_chain_name(to)) ipt.iptable_restore()
def _kill_lb(self, to): pid_file_path = self._make_pid_file_path(to.lbUuid, to.listenerUuid) pid = linux.find_process_by_cmdline([pid_file_path]) if pid: shell.call('kill %s' % pid) shell.call('rm -f %s' % pid_file_path) shell.call('rm -f %s' % self._make_conf_file_path(to.lbUuid, to.listenerUuid)) ipt = iptables.from_iptables_save() ipt.delete_chain(self._make_chain_name(to)) ipt.iptable_restore()
def _refresh_dnsmasq(self, ns_name, conf_file_path): pid = linux.find_process_by_cmdline([conf_file_path]) if not pid: self._restart_dnsmasq(ns_name, conf_file_path) return if self.signal_count > 50: self._restart_dnsmasq(ns_name, conf_file_path) self.signal_count = 0 return shell.call('kill -1 %s' % pid) self.signal_count += 1
def delete(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) keywords = [cmd.token, cmd.proxyHostname, str(cmd.proxyPort)] pid = linux.find_process_by_cmdline(keywords) if pid: shell.call("kill %s" % pid) log_file = self._make_proxy_log_file_name(cmd) shell.call("rm -f %s" % log_file) token_file = self._make_token_file_name(cmd) shell.call("rm -f %s" % token_file) shell.call("iptables-save | grep -- '-A INPUT -p tcp -m tcp --dport %s' > /dev/null && iptables -D INPUT -p tcp -m tcp --dport %s -j ACCEPT" % (cmd.proxyPort, cmd.proxyPort)) logger.debug('deleted a proxy by command: %s' % req[http.REQUEST_BODY]) rsp = AgentResponse() return jsonobject.dumps(rsp)
def _restart_dnsmasq(self, ns_name, conf_file_path): pid = linux.find_process_by_cmdline([conf_file_path]) if pid: linux.kill_process(pid) NS_NAME = ns_name CONF_FILE = conf_file_path DNSMASQ = bash_errorout('which dnsmasq').strip(' \t\r\n') bash_errorout('ip netns exec {{NS_NAME}} {{DNSMASQ}} --conf-file={{CONF_FILE}} ') def check(_): pid = linux.find_process_by_cmdline([conf_file_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('dnsmasq[conf-file:%s] is not running after being started %s seconds' % (conf_file_path, 5))
def _restart_dnsmasq(self, ns_name, conf_file_path): pid = linux.find_process_by_cmdline([conf_file_path]) if pid: linux.kill_process(pid) NS_NAME = ns_name CONF_FILE = conf_file_path DNSMASQ = bash_errorout('which dnsmasq').strip(' \t\r\n') bash_errorout('ip netns exec {{NS_NAME}} {{DNSMASQ}} --conf-file={{CONF_FILE}} ') def check(_): pid = linux.find_process_by_cmdline([conf_file_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('dnsmasq[conf-file:%s] is not running after being started %s seconds' % (conf_file_path, 5))
def delete(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) keywords = [cmd.token, cmd.proxyHostname, str(cmd.proxyPort)] pid = linux.find_process_by_cmdline(keywords) if pid: shell.call("kill %s" % pid) log_file = self._make_proxy_log_file_name(cmd) shell.call("rm -f %s" % log_file) token_file = self._make_token_file_name(cmd) shell.call("rm -f %s" % token_file) shell.call( "iptables-save | grep -- '-A INPUT -p tcp -m tcp --dport %s' > /dev/null && iptables -D INPUT -p tcp -m tcp --dport %s -j ACCEPT" % (cmd.proxyPort, cmd.proxyPort)) logger.debug('deleted a proxy by command: %s' % req[http.REQUEST_BODY]) rsp = AgentResponse() return jsonobject.dumps(rsp)
def _restart_dnsmasq(self, ns_name, conf_file_path): pid = linux.find_process_by_cmdline([conf_file_path]) if pid: linux.kill_process(pid) cmd = '''\ ip netns exec {{ns_name}} /sbin/dnsmasq --conf-file={{conf_file}} || ip netns exec {{ns_name}} /usr/sbin/dnsmasq --conf-file={{conf_file}} ''' tmpt = Template(cmd) cmd = tmpt.render({'ns_name': ns_name, 'conf_file': conf_file_path}) shell.call(cmd) def check(_): pid = linux.find_process_by_cmdline([conf_file_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('dnsmasq[conf-file:%s] is not running after being started %s seconds' % (conf_file_path, 5))
def start_collectd_exporter(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = kvmagent.AgentResponse() eths = bash_o("ls /sys/class/net").split() interfaces = [] for eth in eths: eth = eth.strip(' \t\n\r') if eth == 'lo': continue elif eth.startswith('vnic'): continue elif eth.startswith('outer'): continue elif eth.startswith('br_'): continue elif not eth: continue else: interfaces.append(eth) conf_path = os.path.join(os.path.dirname(cmd.binaryPath), 'collectd.conf') conf = '''Interval {{INTERVAL}} FQDNLookup false LoadPlugin syslog LoadPlugin aggregation LoadPlugin cpu LoadPlugin disk LoadPlugin interface LoadPlugin memory LoadPlugin network LoadPlugin virt <Plugin aggregation> <Aggregation> #Host "unspecified" Plugin "cpu" #PluginInstance "unspecified" Type "cpu" #TypeInstance "unspecified" GroupBy "Host" GroupBy "TypeInstance" CalculateNum false CalculateSum false CalculateAverage true CalculateMinimum false CalculateMaximum false CalculateStddev false </Aggregation> </Plugin> <Plugin cpu> ReportByCpu true ReportByState true ValuesPercentage true </Plugin> <Plugin disk> Disk "/^sd/" Disk "/^hd/" Disk "/^vd/" IgnoreSelected false </Plugin> <Plugin "interface"> {% for i in INTERFACES -%} Interface "{{i}}" {% endfor -%} IgnoreSelected false </Plugin> <Plugin memory> ValuesAbsolute true ValuesPercentage false </Plugin> <Plugin virt> Connection "qemu:///system" RefreshInterval {{INTERVAL}} HostnameFormat name </Plugin> <Plugin network> Server "localhost" "25826" </Plugin> ''' tmpt = Template(conf) conf = tmpt.render({ 'INTERVAL': cmd.interval, 'INTERFACES': interfaces, }) need_restart_collectd = False if os.path.exists(conf_path): with open(conf_path, 'r') as fd: old_conf = fd.read() if old_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True else: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True pid = linux.find_process_by_cmdline(['collectd', conf_path]) if not pid: bash_errorout('collectd -C %s' % conf_path) else: if need_restart_collectd: bash_errorout('kill -9 %s' % pid) bash_errorout('collectd -C %s' % conf_path) pid = linux.find_process_by_cmdline(['collectd_exporter']) if not pid: EXPORTER_PATH = cmd.binaryPath LOG_FILE = os.path.join(os.path.dirname(EXPORTER_PATH), 'collectd_exporter.log') bash_errorout('chmod +x {{EXPORTER_PATH}}') bash_errorout( "nohup {{EXPORTER_PATH}} -collectd.listen-address :25826 >{{LOG_FILE}} 2>&1 < /dev/null &\ndisown" ) return jsonobject.dumps(rsp)
def check(_): pid = linux.find_process_by_cmdline([conf_file_path]) return pid is not None
def apply_userdata(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) conf_folder = os.path.join(self.USERDATA_ROOT, cmd.bridgeName) if not os.path.exists(conf_folder): shell.call('mkdir -p %s' % conf_folder) conf_path = os.path.join(conf_folder, 'lighttpd.conf') http_root = os.path.join(conf_folder, 'html') def write_conf(): conf = '''\ server.document-root = "{{http_root}}" server.port = 80 server.bind = "{{dhcp_server_ip}}" dir-listing.activate = "enable" index-file.names = ( "index.html" ) server.modules += ( "mod_rewrite" ) $HTTP["remoteip"] =~ "^(.*)$" { url.rewrite-once = ( "^/.*/meta-data/(.+)$" => "../%1/meta-data/$1", "^/.*/meta-data$" => "../%1/meta-data", "^/.*/meta-data/$" => "../%1/meta-data/", "^/.*/user-data$" => "../%1/user-data" ) } mimetype.assign = ( ".html" => "text/html", ".txt" => "text/plain", ".jpg" => "image/jpeg", ".png" => "image/png" )''' tmpt = Template(conf) conf = tmpt.render({ 'http_root': http_root, 'dhcp_server_ip': cmd.dhcpServerIp }) with open(conf_path, 'w') as fd: fd.write(conf) if not os.path.exists(conf_path): write_conf() root = os.path.join(http_root, cmd.vmIp) meta_root = os.path.join(root, 'meta-data') if not os.path.exists(meta_root): shell.call('mkdir -p %s' % meta_root) index_file_path = os.path.join(meta_root, 'index.html') with open(index_file_path, 'w') as fd: fd.write('instance-id') instance_id_file_path = os.path.join(meta_root, 'instance-id') with open(instance_id_file_path, 'w') as fd: fd.write(cmd.metadata.vmUuid) userdata_file_path = os.path.join(root, 'user-data') with open(userdata_file_path, 'w') as fd: fd.write(cmd.userdata) pid = linux.find_process_by_cmdline([conf_path]) if not pid: shell.call('ip netns exec %s lighttpd -f %s' % (cmd.bridgeName, conf_path)) def check(_): pid = linux.find_process_by_cmdline([conf_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('lighttpd[conf-file:%s] is not running after being started %s seconds' % (conf_path, 5)) return jsonobject.dumps(ApplyUserdataRsp())
def _apply_userdata(self, to): # set VIP NS_NAME = to.namespaceName DHCP_IP = to.dhcpServerIp INNER_DEV = bash_errorout("ip netns exec {{NS_NAME}} ip addr | grep -w {{DHCP_IP}} | awk '{print $NF}'").strip(' \t\r\n') if not INNER_DEV: raise Exception('cannot find device for the DHCP IP[%s]' % DHCP_IP) ret = bash_r('ip netns exec {{NS_NAME}} ip addr | grep 169.254.169.254 > /dev/null') if ret != 0: bash_errorout('ip netns exec {{NS_NAME}} ip addr add 169.254.169.254 dev {{INNER_DEV}}') # set ebtables BR_NAME = to.bridgeName # BR_NAME is "br_%s_%s" ETH_NAME = BR_NAME.replace('br_', '', 1).replace('_', '.', 1) MAC = bash_errorout("ip netns exec {{NS_NAME}} ip link show {{INNER_DEV}} | grep -w ether | awk '{print $2}'").strip(' \t\r\n') CHAIN_NAME="USERDATA-%s" % BR_NAME ret = bash_r(EBTABLES_CMD + ' -t nat -L {{CHAIN_NAME}} >/dev/null 2>&1') if ret != 0: bash_errorout(EBTABLES_CMD + ' -t nat -N {{CHAIN_NAME}}') if bash_r(EBTABLES_CMD + ' -t nat -L PREROUTING | grep -- "--logical-in {{BR_NAME}} -j {{CHAIN_NAME}}"') != 0: bash_errorout(EBTABLES_CMD + ' -t nat -I PREROUTING --logical-in {{BR_NAME}} -j {{CHAIN_NAME}}') # ebtables has a bug that will eliminate 0 in MAC, for example, aa:bb:0c will become aa:bb:c RULE = "-p IPv4 --ip-dst 169.254.169.254 -j dnat --to-dst %s --dnat-target ACCEPT" % MAC.replace(":0", ":") ret = bash_r(EBTABLES_CMD + ' -t nat -L {{CHAIN_NAME}} | grep -- "{{RULE}}" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -t nat -I {{CHAIN_NAME}} {{RULE}}') ret = bash_r(EBTABLES_CMD + ' -t nat -L {{CHAIN_NAME}} | grep -- "-j RETURN" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -t nat -A {{CHAIN_NAME}} -j RETURN') ret = bash_r(EBTABLES_CMD + ' -L {{CHAIN_NAME}} >/dev/null 2>&1') if ret != 0: bash_errorout(EBTABLES_CMD + ' -N {{CHAIN_NAME}}') ret = bash_r(EBTABLES_CMD + ' -L FORWARD | grep -- "-p ARP --arp-ip-dst 169.254.169.254 -j {{CHAIN_NAME}}" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -I FORWARD -p ARP --arp-ip-dst 169.254.169.254 -j {{CHAIN_NAME}}') ret = bash_r(EBTABLES_CMD + ' -L {{CHAIN_NAME}} | grep -- "-i {{ETH_NAME}} -j DROP" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -I {{CHAIN_NAME}} -i {{ETH_NAME}} -j DROP') ret = bash_r(EBTABLES_CMD + ' -L {{CHAIN_NAME}} | grep -- "-o {{ETH_NAME}} -j DROP" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -I {{CHAIN_NAME}} -o {{ETH_NAME}} -j DROP') ret = bash_r("ebtables-save | grep '\-A {{CHAIN_NAME}} -j RETURN'") if ret != 0: bash_errorout(EBTABLES_CMD + ' -A {{CHAIN_NAME}} -j RETURN') # DNAT port 80 PORT = to.port PORT_CHAIN_NAME = "UD-PORT-%s" % PORT # delete old chains not matching our port OLD_CHAIN = bash_errorout("iptables-save | awk '/^:UD-PORT-/{print substr($1,2)}'").strip(' \n\r\t') if OLD_CHAIN and OLD_CHAIN != CHAIN_NAME: ret = bash_r('iptables-save -t nat | grep -- "-j {{OLD_CHAIN}}"') if ret == 0: bash_r('iptables -t nat -D PREROUTING -j {{OLD_CHAIN}}') bash_errorout('iptables -t nat -F {{OLD_CHAIN}}') bash_errorout('iptables -t nat -X {{OLD_CHAIN}}') ret = bash_r('iptables-save | grep -w ":{{PORT_CHAIN_NAME}}" > /dev/null') if ret != 0: bash_errorout('iptables -t nat -N {{PORT_CHAIN_NAME}}') ret = bash_r('iptables -t nat -L PREROUTING | grep -- "-j {{PORT_CHAIN_NAME}}"') if ret != 0: bash_errorout('iptables -t nat -I PREROUTING -j {{PORT_CHAIN_NAME}}') ret = bash_r('iptables-save -t nat | grep -- "{{PORT_CHAIN_NAME}} -d 169.254.169.254/32 -p tcp -j DNAT --to-destination :{{PORT}}"') if ret != 0: bash_errorout('iptables -t nat -A {{PORT_CHAIN_NAME}} -d 169.254.169.254/32 -p tcp -j DNAT --to-destination :{{PORT}}') conf_folder = os.path.join(self.USERDATA_ROOT, to.namespaceName) if not os.path.exists(conf_folder): shell.call('mkdir -p %s' % conf_folder) conf_path = os.path.join(conf_folder, 'lighttpd.conf') http_root = os.path.join(conf_folder, 'html') conf = '''\ server.document-root = "{{http_root}}" server.port = {{port}} server.bind = "169.254.169.254" dir-listing.activate = "enable" index-file.names = ( "index.html" ) server.modules += ( "mod_rewrite" ) $HTTP["remoteip"] =~ "^(.*)$" { url.rewrite-once = ( "^/.*/meta-data/(.+)$" => "../%1/meta-data/$1", "^/.*/meta-data$" => "../%1/meta-data", "^/.*/meta-data/$" => "../%1/meta-data/", "^/.*/user-data$" => "../%1/user-data" ) } mimetype.assign = ( ".html" => "text/html", ".txt" => "text/plain", ".jpg" => "image/jpeg", ".png" => "image/png" )''' tmpt = Template(conf) conf = tmpt.render({ 'http_root': http_root, 'dhcp_server_ip': to.dhcpServerIp, 'port': to.port }) if not os.path.exists(conf_path): with open(conf_path, 'w') as fd: fd.write(conf) else: with open(conf_path, 'r') as fd: current_conf = fd.read() if current_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) root = os.path.join(http_root, to.vmIp) meta_root = os.path.join(root, 'meta-data') if not os.path.exists(meta_root): shell.call('mkdir -p %s' % meta_root) index_file_path = os.path.join(meta_root, 'index.html') with open(index_file_path, 'w') as fd: fd.write('instance-id') instance_id_file_path = os.path.join(meta_root, 'instance-id') with open(instance_id_file_path, 'w') as fd: fd.write(to.metadata.vmUuid) if to.userdata: userdata_file_path = os.path.join(root, 'user-data') with open(userdata_file_path, 'w') as fd: fd.write(to.userdata) pid = linux.find_process_by_cmdline([conf_path]) if not pid: shell.call('ip netns exec %s lighttpd -f %s' % (to.namespaceName, conf_path)) def check(_): pid = linux.find_process_by_cmdline([conf_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('lighttpd[conf-file:%s] is not running after being started %s seconds' % (conf_path, 5))
def start_collectd_exporter(self, req): cmd = jsonobject.loads(req[http.REQUEST_BODY]) rsp = kvmagent.AgentResponse() eths = bash_o("ls /sys/class/net").split() interfaces = [] for eth in eths: eth = eth.strip(' \t\n\r') if eth == 'lo': continue elif eth.startswith('vnic'): continue elif eth.startswith('outer'): continue elif eth.startswith('br_'): continue elif not eth: continue else: interfaces.append(eth) conf_path = os.path.join(os.path.dirname(cmd.binaryPath), 'collectd.conf') conf = '''Interval {{INTERVAL}} FQDNLookup false LoadPlugin syslog LoadPlugin aggregation LoadPlugin cpu LoadPlugin disk LoadPlugin interface LoadPlugin memory LoadPlugin network LoadPlugin virt <Plugin aggregation> <Aggregation> #Host "unspecified" Plugin "cpu" #PluginInstance "unspecified" Type "cpu" #TypeInstance "unspecified" GroupBy "Host" GroupBy "TypeInstance" CalculateNum false CalculateSum false CalculateAverage true CalculateMinimum false CalculateMaximum false CalculateStddev false </Aggregation> </Plugin> <Plugin cpu> ReportByCpu true ReportByState true ValuesPercentage true </Plugin> <Plugin disk> Disk "/^sd/" Disk "/^hd/" Disk "/^vd/" IgnoreSelected false </Plugin> <Plugin "interface"> {% for i in INTERFACES -%} Interface "{{i}}" {% endfor -%} IgnoreSelected false </Plugin> <Plugin memory> ValuesAbsolute true ValuesPercentage false </Plugin> <Plugin virt> Connection "qemu:///system" RefreshInterval {{INTERVAL}} HostnameFormat name PluginInstanceFormat name </Plugin> <Plugin network> Server "localhost" "25826" </Plugin> ''' tmpt = Template(conf) conf = tmpt.render({ 'INTERVAL': cmd.interval, 'INTERFACES': interfaces, }) need_restart_collectd = False if os.path.exists(conf_path): with open(conf_path, 'r') as fd: old_conf = fd.read() if old_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True else: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True pid = linux.find_process_by_cmdline(['collectd', conf_path]) if not pid: bash_errorout('collectd -C %s' % conf_path) else: if need_restart_collectd: bash_errorout('kill -9 %s' % pid) bash_errorout('collectd -C %s' % conf_path) pid = linux.find_process_by_cmdline(['collectd_exporter']) if not pid: EXPORTER_PATH = cmd.binaryPath LOG_FILE = os.path.join(os.path.dirname(EXPORTER_PATH), 'collectd_exporter.log') bash_errorout('chmod +x {{EXPORTER_PATH}}') bash_errorout("nohup {{EXPORTER_PATH}} -collectd.listen-address :25826 >{{LOG_FILE}} 2>&1 < /dev/null &\ndisown") return jsonobject.dumps(rsp)
def _apply_userdata(self, to): # set VIP NS_NAME = to.namespaceName DHCP_IP = to.dhcpServerIp INNER_DEV = bash_errorout("ip netns exec {{NS_NAME}} ip addr | grep -w {{DHCP_IP}} | awk '{print $NF}'").strip(' \t\r\n') if not INNER_DEV: raise Exception('cannot find device for the DHCP IP[%s]' % DHCP_IP) ret = bash_r('ip netns exec {{NS_NAME}} ip addr | grep 169.254.169.254 > /dev/null') if ret != 0: bash_errorout('ip netns exec {{NS_NAME}} ip addr add 169.254.169.254 dev {{INNER_DEV}}') # set ebtables BR_NAME = to.bridgeName # BR_NAME is "br_%s_%s" ETH_NAME = BR_NAME.replace('br_', '', 1).replace('_', '.', 1) MAC = bash_errorout("ip netns exec {{NS_NAME}} ip link show {{INNER_DEV}} | grep -w ether | awk '{print $2}'").strip(' \t\r\n') CHAIN_NAME="USERDATA-%s" % BR_NAME ret = bash_r('ebtables -t nat -L {{CHAIN_NAME}} >/dev/null 2>&1') if ret != 0: bash_errorout('ebtables -t nat -N {{CHAIN_NAME}}') if bash_r('ebtables -t nat -L PREROUTING | grep -- "--logical-in {{BR_NAME}} -j {{CHAIN_NAME}}"') != 0: bash_errorout('ebtables -t nat -I PREROUTING --logical-in {{BR_NAME}} -j {{CHAIN_NAME}}') # ebtables has a bug that will eliminate 0 in MAC, for example, aa:bb:0c will become aa:bb:c RULE = "-p IPv4 --ip-dst 169.254.169.254 -j dnat --to-dst %s --dnat-target ACCEPT" % MAC.replace(":0", ":") ret = bash_r('ebtables -t nat -L {{CHAIN_NAME}} | grep -- "{{RULE}}" > /dev/null') if ret != 0: bash_errorout('ebtables -t nat -I {{CHAIN_NAME}} {{RULE}}') ret = bash_r('ebtables -t nat -L {{CHAIN_NAME}} | grep -- "-j RETURN" > /dev/null') if ret != 0: bash_errorout('ebtables -t nat -A {{CHAIN_NAME}} -j RETURN') ret = bash_r('ebtables -L {{CHAIN_NAME}} >/dev/null 2>&1') if ret != 0: bash_errorout('ebtables -N {{CHAIN_NAME}}') ret = bash_r('ebtables -L FORWARD | grep -- "-p ARP --arp-ip-dst 169.254.169.254 -j {{CHAIN_NAME}}" > /dev/null') if ret != 0: bash_errorout('ebtables -I FORWARD -p ARP --arp-ip-dst 169.254.169.254 -j {{CHAIN_NAME}}') ret = bash_r('ebtables -L {{CHAIN_NAME}} | grep -- "-i {{ETH_NAME}} -j DROP" > /dev/null') if ret != 0: bash_errorout('ebtables -I {{CHAIN_NAME}} -i {{ETH_NAME}} -j DROP') ret = bash_r('ebtables -L {{CHAIN_NAME}} | grep -- "-o {{ETH_NAME}} -j DROP" > /dev/null') if ret != 0: bash_errorout('ebtables -I {{CHAIN_NAME}} -o {{ETH_NAME}} -j DROP') ret = bash_r("ebtables-save | grep '\-A {{CHAIN_NAME}} -j RETURN'") if ret != 0: bash_errorout('ebtables -A {{CHAIN_NAME}} -j RETURN') # DNAT port 80 PORT = to.port PORT_CHAIN_NAME = "UD-PORT-%s" % PORT # delete old chains not matching our port OLD_CHAIN = bash_errorout("iptables-save | awk '/^:UD-PORT-/{print substr($1,2)}'").strip(' \n\r\t') if OLD_CHAIN and OLD_CHAIN != CHAIN_NAME: ret = bash_r('iptables-save -t nat | grep -- "-j {{OLD_CHAIN}}"') if ret == 0: bash_r('iptables -t nat -D PREROUTING -j {{OLD_CHAIN}}') bash_errorout('iptables -t nat -F {{OLD_CHAIN}}') bash_errorout('iptables -t nat -X {{OLD_CHAIN}}') ret = bash_r('iptables-save | grep -w ":{{PORT_CHAIN_NAME}}" > /dev/null') if ret != 0: bash_errorout('iptables -t nat -N {{PORT_CHAIN_NAME}}') ret = bash_r('iptables -t nat -L PREROUTING | grep -- "-j {{PORT_CHAIN_NAME}}"') if ret != 0: bash_errorout('iptables -t nat -I PREROUTING -j {{PORT_CHAIN_NAME}}') ret = bash_r('iptables-save -t nat | grep -- "{{PORT_CHAIN_NAME}} -d 169.254.169.254/32 -p tcp -j DNAT --to-destination :{{PORT}}"') if ret != 0: bash_errorout('iptables -t nat -A {{PORT_CHAIN_NAME}} -d 169.254.169.254/32 -p tcp -j DNAT --to-destination :{{PORT}}') conf_folder = os.path.join(self.USERDATA_ROOT, to.namespaceName) if not os.path.exists(conf_folder): shell.call('mkdir -p %s' % conf_folder) conf_path = os.path.join(conf_folder, 'lighttpd.conf') http_root = os.path.join(conf_folder, 'html') conf = '''\ server.document-root = "{{http_root}}" server.port = {{port}} server.bind = "169.254.169.254" dir-listing.activate = "enable" index-file.names = ( "index.html" ) server.modules += ( "mod_rewrite" ) $HTTP["remoteip"] =~ "^(.*)$" { url.rewrite-once = ( "^/.*/meta-data/(.+)$" => "../%1/meta-data/$1", "^/.*/meta-data$" => "../%1/meta-data", "^/.*/meta-data/$" => "../%1/meta-data/", "^/.*/user-data$" => "../%1/user-data" ) } mimetype.assign = ( ".html" => "text/html", ".txt" => "text/plain", ".jpg" => "image/jpeg", ".png" => "image/png" )''' tmpt = Template(conf) conf = tmpt.render({ 'http_root': http_root, 'dhcp_server_ip': to.dhcpServerIp, 'port': to.port }) if not os.path.exists(conf_path): with open(conf_path, 'w') as fd: fd.write(conf) else: with open(conf_path, 'r') as fd: current_conf = fd.read() if current_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) root = os.path.join(http_root, to.vmIp) meta_root = os.path.join(root, 'meta-data') if not os.path.exists(meta_root): shell.call('mkdir -p %s' % meta_root) index_file_path = os.path.join(meta_root, 'index.html') with open(index_file_path, 'w') as fd: fd.write('instance-id') instance_id_file_path = os.path.join(meta_root, 'instance-id') with open(instance_id_file_path, 'w') as fd: fd.write(to.metadata.vmUuid) if to.userdata: userdata_file_path = os.path.join(root, 'user-data') with open(userdata_file_path, 'w') as fd: fd.write(to.userdata) pid = linux.find_process_by_cmdline([conf_path]) if not pid: shell.call('ip netns exec %s lighttpd -f %s' % (to.namespaceName, conf_path)) def check(_): pid = linux.find_process_by_cmdline([conf_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('lighttpd[conf-file:%s] is not running after being started %s seconds' % (conf_path, 5))
def check(_): pid = linux.find_process_by_cmdline([conf_file_path]) return pid is not None
def start_exporter(cmd): conf_path = os.path.join(os.path.dirname(cmd.binaryPath), 'collectd.conf') conf = '''Interval {{INTERVAL}} FQDNLookup false LoadPlugin syslog LoadPlugin aggregation LoadPlugin cpu LoadPlugin disk LoadPlugin interface LoadPlugin memory LoadPlugin network LoadPlugin virt <Plugin aggregation> <Aggregation> #Host "unspecified" Plugin "cpu" #PluginInstance "unspecified" Type "cpu" #TypeInstance "unspecified" GroupBy "Host" GroupBy "TypeInstance" CalculateNum false CalculateSum false CalculateAverage true CalculateMinimum false CalculateMaximum false CalculateStddev false </Aggregation> </Plugin> <Plugin cpu> ReportByCpu true ReportByState true ValuesPercentage true </Plugin> <Plugin disk> Disk "/^sd[a-z]$/" Disk "/^hd[a-z]$/" Disk "/^vd[a-z]$/" IgnoreSelected false </Plugin> <Plugin "interface"> {% for i in INTERFACES -%} Interface "{{i}}" {% endfor -%} IgnoreSelected false </Plugin> <Plugin memory> ValuesAbsolute true ValuesPercentage false </Plugin> <Plugin virt> Connection "qemu:///system" RefreshInterval {{INTERVAL}} HostnameFormat name PluginInstanceFormat name BlockDevice "/:hd[a-z]/" IgnoreSelected true </Plugin> <Plugin network> Server "localhost" "25826" </Plugin> ''' tmpt = Template(conf) conf = tmpt.render({ 'INTERVAL': cmd.interval, 'INTERFACES': interfaces, }) need_restart_collectd = False if os.path.exists(conf_path): with open(conf_path, 'r') as fd: old_conf = fd.read() if old_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True else: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True cpid = linux.find_process_by_cmdline(['collectd', conf_path]) mpid = linux.find_process_by_cmdline(['collectdmon', conf_path]) if not cpid: bash_errorout('collectdmon -- -C %s' % conf_path) else: if need_restart_collectd: if not mpid: bash_errorout('kill -TERM %s' % cpid) bash_errorout('collectdmon -- -C %s' % conf_path) else: bash_errorout('kill -HUP %s' % mpid) pid = linux.find_process_by_cmdline([cmd.binaryPath]) if not pid: EXPORTER_PATH = cmd.binaryPath LOG_FILE = os.path.join(os.path.dirname(EXPORTER_PATH), cmd.binaryPath + '.log') ARGUMENTS = cmd.startupArguments if not ARGUMENTS: ARGUMENTS = "" bash_errorout('chmod +x {{EXPORTER_PATH}}') bash_errorout("nohup {{EXPORTER_PATH}} {{ARGUMENTS}} >{{LOG_FILE}} 2>&1 < /dev/null &\ndisown")
def _apply_userdata(self, to): p = UserDataEnv(to.bridgeName, to.namespaceName) INNER_DEV = None DHCP_IP = None NS_NAME = to.namespaceName if not to.hasattr("dhcpServerIp"): p.prepare() INNER_DEV = p.inner_dev else: DHCP_IP = to.dhcpServerIp INNER_DEV = bash_errorout( "ip netns exec {{NS_NAME}} ip addr | grep -w {{DHCP_IP}} | awk '{print $NF}'" ).strip(' \t\r\n') if not INNER_DEV: p.prepare() INNER_DEV = p.inner_dev if not INNER_DEV: raise Exception('cannot find device for the DHCP IP[%s]' % DHCP_IP) ret = bash_r( 'ip netns exec {{NS_NAME}} ip addr | grep 169.254.169.254 > /dev/null' ) if (ret != 0 and INNER_DEV != None): bash_errorout( 'ip netns exec {{NS_NAME}} ip addr add 169.254.169.254 dev {{INNER_DEV}}' ) r, o = bash_ro('ip netns exec {{NS_NAME}} ip r | wc -l') if not to.hasattr("dhcpServerIp") and int(o) == 0: bash_errorout( 'ip netns exec {{NS_NAME}} ip r add default dev {{INNER_DEV}}') # set ebtables BR_NAME = to.bridgeName # BR_NAME is "br_%s_%s" ETH_NAME = BR_NAME.replace('br_', '', 1).replace('_', '.', 1) MAC = bash_errorout( "ip netns exec {{NS_NAME}} ip link show {{INNER_DEV}} | grep -w ether | awk '{print $2}'" ).strip(' \t\r\n') CHAIN_NAME = "USERDATA-%s" % BR_NAME ret = bash_r(EBTABLES_CMD + ' -t nat -L {{CHAIN_NAME}} >/dev/null 2>&1') if ret != 0: bash_errorout(EBTABLES_CMD + ' -t nat -N {{CHAIN_NAME}}') if bash_r( EBTABLES_CMD + ' -t nat -L PREROUTING | grep -- "--logical-in {{BR_NAME}} -j {{CHAIN_NAME}}"' ) != 0: bash_errorout( EBTABLES_CMD + ' -t nat -I PREROUTING --logical-in {{BR_NAME}} -j {{CHAIN_NAME}}' ) # ebtables has a bug that will eliminate 0 in MAC, for example, aa:bb:0c will become aa:bb:c RULE = "-p IPv4 --ip-dst 169.254.169.254 -j dnat --to-dst %s --dnat-target ACCEPT" % MAC.replace( ":0", ":") ret = bash_r( EBTABLES_CMD + ' -t nat -L {{CHAIN_NAME}} | grep -- "{{RULE}}" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -t nat -I {{CHAIN_NAME}} {{RULE}}') ret = bash_r( EBTABLES_CMD + ' -t nat -L {{CHAIN_NAME}} | grep -- "-j RETURN" > /dev/null') if ret != 0: bash_errorout(EBTABLES_CMD + ' -t nat -A {{CHAIN_NAME}} -j RETURN') ret = bash_r(EBTABLES_CMD + ' -L {{CHAIN_NAME}} >/dev/null 2>&1') if ret != 0: bash_errorout(EBTABLES_CMD + ' -N {{CHAIN_NAME}}') ret = bash_r( EBTABLES_CMD + ' -L FORWARD | grep -- "-p ARP --arp-ip-dst 169.254.169.254 -j {{CHAIN_NAME}}" > /dev/null' ) if ret != 0: bash_errorout( EBTABLES_CMD + ' -I FORWARD -p ARP --arp-ip-dst 169.254.169.254 -j {{CHAIN_NAME}}' ) ret = bash_r( EBTABLES_CMD + ' -L {{CHAIN_NAME}} | grep -- "-i {{ETH_NAME}} -j DROP" > /dev/null' ) if ret != 0: bash_errorout(EBTABLES_CMD + ' -I {{CHAIN_NAME}} -i {{ETH_NAME}} -j DROP') ret = bash_r( EBTABLES_CMD + ' -L {{CHAIN_NAME}} | grep -- "-o {{ETH_NAME}} -j DROP" > /dev/null' ) if ret != 0: bash_errorout(EBTABLES_CMD + ' -I {{CHAIN_NAME}} -o {{ETH_NAME}} -j DROP') ret = bash_r("ebtables-save | grep '\-A {{CHAIN_NAME}} -j RETURN'") if ret != 0: bash_errorout(EBTABLES_CMD + ' -A {{CHAIN_NAME}} -j RETURN') self.work_userdata_iptables(CHAIN_NAME, to) conf_folder = os.path.join(self.USERDATA_ROOT, to.namespaceName) if not os.path.exists(conf_folder): shell.call('mkdir -p %s' % conf_folder) conf_path = os.path.join(conf_folder, 'lighttpd.conf') http_root = os.path.join(conf_folder, 'html') conf = '''\ server.document-root = "{{http_root}}" server.port = {{port}} server.bind = "169.254.169.254" dir-listing.activate = "enable" index-file.names = ( "index.html" ) server.modules += ( "mod_rewrite" ) $HTTP["remoteip"] =~ "^(.*)$" { url.rewrite-once = ( "^/.*/meta-data/(.+)$" => "../%1/meta-data/$1", "^/.*/meta-data$" => "../%1/meta-data", "^/.*/meta-data/$" => "../%1/meta-data/", "^/.*/user-data$" => "../%1/user-data", "^/.*/user_data$" => "../%1/user_data", "^/.*/meta_data.json$" => "../%1/meta_data.json", "^/.*/password$" => "../%1/password", "^/.*/$" => "../%1/$1" ) dir-listing.activate = "enable" } mimetype.assign = ( ".html" => "text/html", ".txt" => "text/plain", ".jpg" => "image/jpeg", ".png" => "image/png" )''' tmpt = Template(conf) conf = tmpt.render({'http_root': http_root, 'port': to.port}) if not os.path.exists(conf_path): with open(conf_path, 'w') as fd: fd.write(conf) else: with open(conf_path, 'r') as fd: current_conf = fd.read() if current_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) meta_data_json = '''\ { "uuid": "{{vmInstanceUuid}}" }''' tmpt = Template(meta_data_json) conf = tmpt.render({'vmInstanceUuid': to.metadata.vmUuid}) root = os.path.join(http_root, to.vmIp) meta_root = os.path.join(root, 'meta-data') if not os.path.exists(meta_root): shell.call('mkdir -p %s' % meta_root) index_file_path = os.path.join(meta_root, 'index.html') with open(index_file_path, 'w') as fd: fd.write('instance-id') instance_id_file_path = os.path.join(meta_root, 'instance-id') with open(instance_id_file_path, 'w') as fd: fd.write(to.metadata.vmUuid) if to.userdata: userdata_file_path = os.path.join(root, 'user-data') with open(userdata_file_path, 'w') as fd: fd.write(to.userdata) windows_meta_data_json_path = os.path.join(root, 'meta_data.json') with open(windows_meta_data_json_path, 'w') as fd: fd.write(conf) windows_userdata_file_path = os.path.join(root, 'user_data') with open(windows_userdata_file_path, 'w') as fd: fd.write(to.userdata) windows_meta_data_password = os.path.join(root, 'password') with open(windows_meta_data_password, 'w') as fd: fd.write('') pid = linux.find_process_by_cmdline([conf_path]) if not pid: shell.call('ip netns exec %s lighttpd -f %s' % (to.namespaceName, conf_path)) def check(_): pid = linux.find_process_by_cmdline([conf_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception( 'lighttpd[conf-file:%s] is not running after being started %s seconds' % (conf_path, 5))
def _apply_userdata(self, to): set_vip_cmd = ''' NS_NAME={{ns_name}} DHCP_IP={{dhcp_ip}} NS="ip netns exec $NS_NAME" exit_on_error() { if [ $? -ne 0 ]; then echo "error on line $1" exit 1 fi } eval $NS ip addr | grep 169.254.169.254 > /dev/null if [ $? -eq 0 ]; then exit 0 fi eth=`eval $NS ip addr | grep -w $DHCP_IP | awk '{print $NF}'` exit_on_error $LINENO if [ x$eth == "x" ]; then echo "cannot find device for the DHCP IP $DHCP_IP" exit 1 fi eval $NS ip addr add 169.254.169.254 dev $eth exit_on_error $LINENO exit 0 ''' tmpt = Template(set_vip_cmd) set_vip_cmd = tmpt.render({ 'ns_name': to.bridgeName, 'dhcp_ip': to.dhcpServerIp, }) shell.call(set_vip_cmd) set_ebtables = ''' BR_NAME={{br_name}} NS_NAME={{ns_name}} NS="ip netns exec $NS_NAME" exit_on_error() { if [ $? -ne 0 ]; then echo "error on line $1" exit 1 fi } eth=`eval $NS ip addr | grep 169.254.169.254 | awk '{print $NF}'` mac=`eval $NS ip link show $eth | grep -w ether | awk '{print $2}'` exit_on_error $LINENO CHAIN_NAME="USERDATA-$BR_NAME" ebtables-save | grep -w ":$CHAIN_NAME" > /dev/null if [ $? -ne 0 ]; then ebtables -t nat -N $CHAIN_NAME exit_on_error $LINENO ebtables -t nat -I PREROUTING --logical-in $BR_NAME -j $CHAIN_NAME exit_on_error $LINENO fi rule="$CHAIN_NAME -p IPv4 --ip-dst 169.254.169.254 -j dnat --to-dst $mac --dnat-target ACCEPT" ebtables-save | grep -- "$rule" > /dev/null if [ $? -ne 0 ]; then ebtables -t nat -I $rule exit_on_error $LINENO fi exit 0 ''' tmpt = Template(set_ebtables) set_ebtables = tmpt.render({ 'br_name': to.bridgeName, 'ns_name': to.bridgeName, }) shell.call(set_ebtables) dnat_port_cmd = ''' PORT={{port}} CHAIN_NAME="UD-PORT-$PORT" exit_on_error() { if [ $? -ne 0 ]; then echo "error on line $1" exit 1 fi } # delete old chains not matching our port old_chain=`iptables-save | awk '/^:UD-PORT-/{print substr($1,2)}'` if [ x"$old_chain" != "x" -a $CHAIN_NAME != $old_chain ]; then iptables -t nat -F $old_chain exit_on_error $LINENO iptables -t nat -X $old_chain exit_on_error $LINENO fi iptables-save | grep -w ":$CHAIN_NAME" > /dev/null if [ $? -ne 0 ]; then iptables -t nat -N $CHAIN_NAME exit_on_error $LINENO iptables -t nat -I PREROUTING -j $CHAIN_NAME exit_on_error $LINENO fi iptables-save -t nat | grep -- "$CHAIN_NAME -d 169.254.169.254/32 -p tcp -j DNAT --to-destination :$PORT" > /dev/null || iptables -t nat -A $CHAIN_NAME -d 169.254.169.254/32 -p tcp -j DNAT --to-destination :$PORT exit_on_error $LINENO exit 0 ''' tmpt = Template(dnat_port_cmd) dnat_port_cmd = tmpt.render({ 'port': to.port }) shell.call(dnat_port_cmd) conf_folder = os.path.join(self.USERDATA_ROOT, to.bridgeName) if not os.path.exists(conf_folder): shell.call('mkdir -p %s' % conf_folder) conf_path = os.path.join(conf_folder, 'lighttpd.conf') http_root = os.path.join(conf_folder, 'html') conf = '''\ server.document-root = "{{http_root}}" server.port = {{port}} server.bind = "169.254.169.254" dir-listing.activate = "enable" index-file.names = ( "index.html" ) server.modules += ( "mod_rewrite" ) $HTTP["remoteip"] =~ "^(.*)$" { url.rewrite-once = ( "^/.*/meta-data/(.+)$" => "../%1/meta-data/$1", "^/.*/meta-data$" => "../%1/meta-data", "^/.*/meta-data/$" => "../%1/meta-data/", "^/.*/user-data$" => "../%1/user-data" ) } mimetype.assign = ( ".html" => "text/html", ".txt" => "text/plain", ".jpg" => "image/jpeg", ".png" => "image/png" )''' tmpt = Template(conf) conf = tmpt.render({ 'http_root': http_root, 'dhcp_server_ip': to.dhcpServerIp, 'port': to.port }) if not os.path.exists(conf_path): with open(conf_path, 'w') as fd: fd.write(conf) else: with open(conf_path, 'r') as fd: current_conf = fd.read() if current_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) root = os.path.join(http_root, to.vmIp) meta_root = os.path.join(root, 'meta-data') if not os.path.exists(meta_root): shell.call('mkdir -p %s' % meta_root) index_file_path = os.path.join(meta_root, 'index.html') with open(index_file_path, 'w') as fd: fd.write('instance-id') instance_id_file_path = os.path.join(meta_root, 'instance-id') with open(instance_id_file_path, 'w') as fd: fd.write(to.metadata.vmUuid) if to.userdata: userdata_file_path = os.path.join(root, 'user-data') with open(userdata_file_path, 'w') as fd: fd.write(to.userdata) pid = linux.find_process_by_cmdline([conf_path]) if not pid: shell.call('ip netns exec %s lighttpd -f %s' % (to.bridgeName, conf_path)) def check(_): pid = linux.find_process_by_cmdline([conf_path]) return pid is not None if not linux.wait_callback_success(check, None, 5): raise Exception('lighttpd[conf-file:%s] is not running after being started %s seconds' % (conf_path, 5))
def start_exporter(cmd): conf_path = os.path.join(os.path.dirname(cmd.binaryPath), 'collectd.conf') conf = '''Interval {{INTERVAL}} FQDNLookup false LoadPlugin syslog LoadPlugin aggregation LoadPlugin cpu LoadPlugin disk LoadPlugin interface LoadPlugin memory LoadPlugin network LoadPlugin virt <Plugin aggregation> <Aggregation> #Host "unspecified" Plugin "cpu" #PluginInstance "unspecified" Type "cpu" #TypeInstance "unspecified" GroupBy "Host" GroupBy "TypeInstance" CalculateNum false CalculateSum false CalculateAverage true CalculateMinimum false CalculateMaximum false CalculateStddev false </Aggregation> </Plugin> <Plugin cpu> ReportByCpu true ReportByState true ValuesPercentage true </Plugin> <Plugin disk> Disk "/^sd[a-z]$/" Disk "/^hd[a-z]$/" Disk "/^vd[a-z]$/" IgnoreSelected false </Plugin> <Plugin "interface"> {% for i in INTERFACES -%} Interface "{{i}}" {% endfor -%} IgnoreSelected false </Plugin> <Plugin memory> ValuesAbsolute true ValuesPercentage false </Plugin> <Plugin virt> Connection "qemu:///system" RefreshInterval {{INTERVAL}} HostnameFormat name PluginInstanceFormat name BlockDevice "/:hd[a-z]/" IgnoreSelected true </Plugin> <Plugin network> Server "localhost" "25826" </Plugin> ''' tmpt = Template(conf) conf = tmpt.render({ 'INTERVAL': cmd.interval, 'INTERFACES': interfaces, }) need_restart_collectd = False if os.path.exists(conf_path): with open(conf_path, 'r') as fd: old_conf = fd.read() if old_conf != conf: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True else: with open(conf_path, 'w') as fd: fd.write(conf) need_restart_collectd = True cpid = linux.find_process_by_cmdline(['collectd', conf_path]) mpid = linux.find_process_by_cmdline(['collectdmon', conf_path]) if not cpid: bash_errorout('collectdmon -- -C %s' % conf_path) else: if need_restart_collectd: if not mpid: bash_errorout('kill -TERM %s' % cpid) bash_errorout('collectdmon -- -C %s' % conf_path) else: bash_errorout('kill -HUP %s' % mpid) pid = linux.find_process_by_cmdline([cmd.binaryPath]) if not pid: EXPORTER_PATH = cmd.binaryPath LOG_FILE = os.path.join(os.path.dirname(EXPORTER_PATH), cmd.binaryPath + '.log') ARGUMENTS = cmd.startupArguments if not ARGUMENTS: ARGUMENTS = "" bash_errorout('chmod +x {{EXPORTER_PATH}}') bash_errorout( "nohup {{EXPORTER_PATH}} {{ARGUMENTS}} >{{LOG_FILE}} 2>&1 < /dev/null &\ndisown" )