Add un/register container IP
This commit is contained in:
		
							parent
							
								
									fa70f85acb
								
							
						
					
					
						commit
						cff204ca46
					
				@ -44,6 +44,14 @@ parser_disable_autostart.add_argument('app', help='Application name')
 | 
				
			|||||||
parser_rebuild_issue = subparsers.add_parser('rebuild-issue', help='Rebuilds /etc/issue using current settings - used on VM startup')
 | 
					parser_rebuild_issue = subparsers.add_parser('rebuild-issue', help='Rebuilds /etc/issue using current settings - used on VM startup')
 | 
				
			||||||
parser_rebuild_issue.set_defaults(action='rebuild-issue')
 | 
					parser_rebuild_issue.set_defaults(action='rebuild-issue')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parser_register_container = subparsers.add_parser('register-container', help='Register and assigns IP to an application container. Intended to be used with LXC hooks')
 | 
				
			||||||
 | 
					parser_register_container.add_argument('lxc', nargs=argparse.REMAINDER)
 | 
				
			||||||
 | 
					parser_register_container.set_defaults(action='register-container')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parser_unregister_container = subparsers.add_parser('unregister-container', help='Removes IP assignment for an application container. Intended to be used with LXC hooks')
 | 
				
			||||||
 | 
					parser_unregister_container.add_argument('lxc', nargs=argparse.REMAINDER)
 | 
				
			||||||
 | 
					parser_unregister_container.set_defaults(action='unregister-container')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
parser_register_proxy = subparsers.add_parser('register-proxy', help='Rebuilds nginx proxy target for an application container')
 | 
					parser_register_proxy = subparsers.add_parser('register-proxy', help='Rebuilds nginx proxy target for an application container')
 | 
				
			||||||
parser_register_proxy.set_defaults(action='register-proxy')
 | 
					parser_register_proxy.set_defaults(action='register-proxy')
 | 
				
			||||||
parser_register_proxy.add_argument('app', help='Application name')
 | 
					parser_register_proxy.add_argument('app', help='Application name')
 | 
				
			||||||
@ -94,6 +102,10 @@ elif args.action == 'disable-autostart':
 | 
				
			|||||||
    mgr.disable_autostart(args.app)
 | 
					    mgr.disable_autostart(args.app)
 | 
				
			||||||
elif args.action == 'rebuild-issue':
 | 
					elif args.action == 'rebuild-issue':
 | 
				
			||||||
    mgr.rebuild_issue()
 | 
					    mgr.rebuild_issue()
 | 
				
			||||||
 | 
					elif args.action == 'register-container':
 | 
				
			||||||
 | 
					    mgr.register_container()
 | 
				
			||||||
 | 
					elif args.action == 'unregister-container':
 | 
				
			||||||
 | 
					    mgr.unregister_container()
 | 
				
			||||||
elif args.action == 'register-proxy':
 | 
					elif args.action == 'register-proxy':
 | 
				
			||||||
    mgr.register_proxy(args.app)
 | 
					    mgr.register_proxy(args.app)
 | 
				
			||||||
elif args.action == 'unregister-proxy':
 | 
					elif args.action == 'unregister-proxy':
 | 
				
			||||||
 | 
				
			|||||||
@ -208,6 +208,19 @@ class VMMgr:
 | 
				
			|||||||
            raise validator.InvalidValueException('app', app)
 | 
					            raise validator.InvalidValueException('app', app)
 | 
				
			||||||
        subprocess.run(['/sbin/rc-update', 'del', app])
 | 
					        subprocess.run(['/sbin/rc-update', 'del', app])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def register_container(self):
 | 
				
			||||||
 | 
					        # Set IP of a container based on values given via lxc.hook.start-host hook
 | 
				
			||||||
 | 
					        app = os.environ['LXC_NAME']
 | 
				
			||||||
 | 
					        pid = os.environ['LXC_PID']
 | 
				
			||||||
 | 
					        ip = tools.get_unused_ip()
 | 
				
			||||||
 | 
					        tools.update_hosts_lease(ip, app)
 | 
				
			||||||
 | 
					        tools.set_container_ip(pid, ip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unregister_container(self):
 | 
				
			||||||
 | 
					        # Unset IP of a container based on values given via lxc.hook.post-stop hook
 | 
				
			||||||
 | 
					        app = os.environ['LXC_NAME']
 | 
				
			||||||
 | 
					        tools.update_hosts_lease(None, app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def register_proxy(self, app):
 | 
					    def register_proxy(self, app):
 | 
				
			||||||
        # Rebuild nginx configuration using IP of referenced app container and reload nginx
 | 
					        # Rebuild nginx configuration using IP of referenced app container and reload nginx
 | 
				
			||||||
        if not validator.is_valid_app(app, self.conf):
 | 
					        if not validator.is_valid_app(app, self.conf):
 | 
				
			||||||
 | 
				
			|||||||
@ -16,13 +16,6 @@ def compile_url(domain, port, proto='https'):
 | 
				
			|||||||
    host = '{}{}'.format(domain, port)
 | 
					    host = '{}{}'.format(domain, port)
 | 
				
			||||||
    return '{}://{}'.format(proto, host) if proto is not None else host
 | 
					    return '{}://{}'.format(proto, host) if proto is not None else host
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_container_ip(app):
 | 
					 | 
				
			||||||
    # Return an IP address of a container. If the container is not running, return address from IPv6 discard prefix instead
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        return subprocess.run(['/usr/bin/docker', 'inspect', '-f', '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}', app], check=True, stdout=subprocess.PIPE).stdout.decode().strip()
 | 
					 | 
				
			||||||
    except:
 | 
					 | 
				
			||||||
        return NULL_IP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def get_local_ipv4():
 | 
					def get_local_ipv4():
 | 
				
			||||||
    # Return first routable IPv4 address
 | 
					    # Return first routable IPv4 address
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
@ -122,3 +115,41 @@ def shutdown_vm():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def reboot_vm():
 | 
					def reboot_vm():
 | 
				
			||||||
    subprocess.run(['/sbin/reboot'])
 | 
					    subprocess.run(['/sbin/reboot'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_unused_ip():
 | 
				
			||||||
 | 
					    # This is a poor man's DHCP server which uses /etc/hosts as lease database
 | 
				
			||||||
 | 
					    # Leases the first unused IP from range 172.17.0.0/16
 | 
				
			||||||
 | 
					    leased = []
 | 
				
			||||||
 | 
					    with open('/etc/hosts', 'r') as fd:
 | 
				
			||||||
 | 
					        for line in fd.read().splitlines():
 | 
				
			||||||
 | 
					            if line.startswith('172.17'):
 | 
				
			||||||
 | 
					                ip = line.split()[0].split('.')
 | 
				
			||||||
 | 
					                leased.append(int(ip[2]) * 256 + int(ip[3]))
 | 
				
			||||||
 | 
					    for i in range(1, 65534):
 | 
				
			||||||
 | 
					        if i not in leased:
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					    return '172.17.{}.{}'. format(i // 256, i % 256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def update_hosts_lease(ip, app):
 | 
				
			||||||
 | 
					    hosts = []
 | 
				
			||||||
 | 
					    with open('/etc/hosts', 'r') as fd:
 | 
				
			||||||
 | 
					        for line in fd:
 | 
				
			||||||
 | 
					            if not line.strip().endswith(' {}'.format(app)):
 | 
				
			||||||
 | 
					                hosts.append(line)
 | 
				
			||||||
 | 
					    if ip:
 | 
				
			||||||
 | 
					        hosts.append('{} {}\n'.format(ip, app))
 | 
				
			||||||
 | 
					    with open('/etc/hosts', 'w') as fd:
 | 
				
			||||||
 | 
					        fd.writelines(hosts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_container_ip(app):
 | 
				
			||||||
 | 
					    # Return an IP of a container. If the container doesn't exist, return address from IPv6 discard prefix instead
 | 
				
			||||||
 | 
					    with open('/etc/hosts', 'r') as fd:
 | 
				
			||||||
 | 
					        for line in fd:
 | 
				
			||||||
 | 
					            if line.strip().endswith(' {}'.format(app)):
 | 
				
			||||||
 | 
					                return line.split()[0]
 | 
				
			||||||
 | 
					    return NULL_IP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def set_container_ip(pid, ip):
 | 
				
			||||||
 | 
					    # Set IP in container based on PID given via lxc.hook.start-host hook
 | 
				
			||||||
 | 
					    cmd = 'ip addr add {}/16 broadcast 172.17.255.255 dev eth0 && ip route add default via 172.17.0.1'.format(ip)
 | 
				
			||||||
 | 
					    subprocess.run(['nsenter', '-a', '-t', pid, '--', '/bin/sh', '-c', cmd])
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,6 @@ lxc.uts.name = {name}
 | 
				
			|||||||
lxc.net.0.type = veth
 | 
					lxc.net.0.type = veth
 | 
				
			||||||
lxc.net.0.link = lxcbr0
 | 
					lxc.net.0.link = lxcbr0
 | 
				
			||||||
lxc.net.0.flags = up
 | 
					lxc.net.0.flags = up
 | 
				
			||||||
lxc.net.0.ipv4.address = 172.17.0.254/16
 | 
					 | 
				
			||||||
lxc.net.0.ipv4.gateway = auto
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Volumes
 | 
					# Volumes
 | 
				
			||||||
lxc.rootfs.path = {rootfs}
 | 
					lxc.rootfs.path = {rootfs}
 | 
				
			||||||
@ -43,6 +41,8 @@ lxc.console.logfile = /var/log/lxc/{name}.log
 | 
				
			|||||||
# Other
 | 
					# Other
 | 
				
			||||||
lxc.arch = x86_64
 | 
					lxc.arch = x86_64
 | 
				
			||||||
lxc.cap.drop = sys_admin
 | 
					lxc.cap.drop = sys_admin
 | 
				
			||||||
 | 
					lxc.hook.start-host = /usr/bin/vmmgr register-container
 | 
				
			||||||
 | 
					lxc.hook.post-stop = /usr/bin/vmmgr unregister-container
 | 
				
			||||||
lxc.include = /usr/share/lxc/config/common.conf
 | 
					lxc.include = /usr/share/lxc/config/common.conf
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user