apache.py 6.43 KB
Newer Older
hxquangnhat's avatar
hxquangnhat committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copyright (c) 2016, Quang-Nhat Hoang-Xuan
#
# 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.

16
"""Proxifying using Apache2 Container."""
hxquangnhat's avatar
hxquangnhat committed
17
18
19

import time
import logging
20
import random
hxquangnhat's avatar
hxquangnhat committed
21
import docker
hxquangnhat's avatar
hxquangnhat committed
22
23
24

import zoe_api.proxy.base
import zoe_api.api_endpoint
qhoangxuan's avatar
qhoangxuan committed
25
from zoe_master.backends.old_swarm.api_client import SwarmClient
26
from zoe_master.backends.kubernetes.api_client import KubernetesClient
hxquangnhat's avatar
hxquangnhat committed
27
28
29
30
31
32
from zoe_lib.config import get_conf

log = logging.getLogger(__name__)

class ApacheProxy(zoe_api.proxy.base.BaseProxy):
    """Apache proxy class."""
33
    def __init__(self, apiEndpoint):
hxquangnhat's avatar
hxquangnhat committed
34
35
        self.api_endpoint = apiEndpoint

hxquangnhat's avatar
hxquangnhat committed
36
37
    def proxify(self, uid, role, execution_id): #pylint: disable=too-many-locals
        """Proxify function."""
hxquangnhat's avatar
hxquangnhat committed
38
        try:
39
            #Wait until all the services get created and started to be able to get the backend_id
hxquangnhat's avatar
hxquangnhat committed
40
            while self.api_endpoint.execution_by_id(uid, role, execution_id).status != 'running':
hxquangnhat's avatar
hxquangnhat committed
41
42
43
                log.info('Waiting for all services get started...')
                time.sleep(1)

hxquangnhat's avatar
hxquangnhat committed
44
45
46
47
48
49
            exe = self.api_endpoint.execution_by_id(uid, role, execution_id)
            lth = len(exe.services)

            while lth != 0:
                exe = self.api_endpoint.execution_by_id(uid, role, execution_id)
                lth = len(exe.services)
qhoangxuan's avatar
qhoangxuan committed
50
                for srv in exe.services:
hxquangnhat's avatar
hxquangnhat committed
51
                    if srv.backend_id is None:
qhoangxuan's avatar
qhoangxuan committed
52
53
                        time.sleep(1)
                    else:
hxquangnhat's avatar
hxquangnhat committed
54
55
                        lth = lth - 1

56
            #Start proxifying by adding entry to use proxypass and proxypassreverse in apache2 config file
hxquangnhat's avatar
hxquangnhat committed
57
            for srv in exe.services:
hxquangnhat's avatar
hxquangnhat committed
58
                ip, port = None, None
hxquangnhat's avatar
hxquangnhat committed
59

60
61
                if get_conf().backend == 'OldSwarm':
                    swarm = SwarmClient(get_conf())
hxquangnhat's avatar
hxquangnhat committed
62
                    s_info = swarm.inspect_container(srv.backend_id)
hxquangnhat's avatar
hxquangnhat committed
63
64
65
66
67
68
69
70
71
72
73
74
75
                    port_list = s_info['ports']

                    for key, val in port_list.items():
                        exposed_port = key.split('/tcp')[0]
                        if val != None:
                            ip = val[0]
                            port = val[1]

                        base_path = '/zoe/' + uid + '/' + str(execution_id) + '/' + srv.name + '/' + exposed_port
                        original_path = str(ip) + ':' + str(port) + base_path

                        if ip is not None and port is not None:
                            log.info('Proxifying %s', srv.name + ' port ' + exposed_port)
hxquangnhat's avatar
hxquangnhat committed
76
                            self.dispatch_to_docker(base_path, original_path)
77
78
79
                else:
                    kube = KubernetesClient(get_conf())
                    s_info = kube.inspect_service(srv.dns_name)
hxquangnhat's avatar
hxquangnhat committed
80
81
82
83

                    kube_nodes = kube.info().nodes
                    host_ip = random.choice(kube_nodes).name

84
85
86
87
88
                    while 'nodePort' not in s_info['port_forwarding'][0]:
                        log.info('Waiting for service get started before proxifying...')
                        s_info = kube.inspect_service(srv.dns_name)
                        time.sleep(0.5)

hxquangnhat's avatar
hxquangnhat committed
89
90
91
92
93
                    ip = host_ip
                    port = s_info['port_forwarding'][0]['nodePort']
                    exposed_port = s_info['port_forwarding'][0]['port']
                    base_path = '/zoe/' + uid + '/' + str(execution_id) + '/' + srv.name + '/' + str(exposed_port)
                    original_path = str(ip) + ':' + str(port) + base_path
94

hxquangnhat's avatar
hxquangnhat committed
95
96
                    if ip is not None and port is not None:
                        log.info('Proxifying %s', srv.name + ' port ' + str(exposed_port))
hxquangnhat's avatar
hxquangnhat committed
97
                        self.dispatch_to_docker(base_path, original_path)
hxquangnhat's avatar
hxquangnhat committed
98
99
100
101
102

        except Exception as ex:
            log.error(ex)

    def dispatch_to_docker(self, base_path, original_path):
hxquangnhat's avatar
hxquangnhat committed
103
104
105
106
        """
        The apache2 server is running inside a container
        Adding new entries with the proxy path and the ip:port of the application to the apache2 config file
        """
hxquangnhat's avatar
hxquangnhat committed
107
108
109
110
111
112
113
114
115
        proxy = ['ProxyPass ' + base_path + '/api/kernels/ ws://' + original_path + '/api/kernels/',
                 'ProxyPassReverse ' + base_path + '/api/kernels/ ws://' + original_path + '/api/kernels/',
                 'ProxyPass ' + base_path + '/terminals/websocket/ ws://' + original_path + '/terminals/websocket/',
                 'ProxyPassReverse ' + base_path + '/terminals/websocket/ ws://' + original_path + '/terminals/websocket/',
                 'ProxyPass ' + base_path + ' http://' + original_path,
                 'ProxyPassReverse ' + base_path + ' http://' + original_path,
                 '',
                 '</VirtualHost>']

116
        docker_client = docker.Client(base_url=get_conf().proxy_docker_sock)
hxquangnhat's avatar
hxquangnhat committed
117

hxquangnhat's avatar
hxquangnhat committed
118
119
120
        del_command = "sed -i '$ d' " + get_conf().proxy_config_file # /etc/apache2/sites-available/all.conf"
        del_id = docker_client.exec_create(get_conf().proxy_container, del_command)
        docker_client.exec_start(del_id)
hxquangnhat's avatar
hxquangnhat committed
121

hxquangnhat's avatar
hxquangnhat committed
122
123
124
125
        for entry in proxy:
            command = 'bash -c "echo ' + "'" + entry + "'" + '  >> /etc/apache2/sites-available/all.conf"'
            execution_id = docker_client.exec_create(get_conf().proxy_container, command)
            docker_client.exec_start(execution_id)
hxquangnhat's avatar
hxquangnhat committed
126

hxquangnhat's avatar
hxquangnhat committed
127
128
129
        reload_command = 'service apache2 reload'
        reload_id = docker_client.exec_create(get_conf().proxy_container, reload_command)
        docker_client.exec_start(reload_id)
hxquangnhat's avatar
hxquangnhat committed
130

131
    #Simply remove the added entries at the apache2 config file when terminating applcations
hxquangnhat's avatar
hxquangnhat committed
132
133
134
    def unproxify(self, uid, role, execution_id):
        log.info('Unproxifying for user %s - execution %s', uid, str(execution_id))
        pattern = '/zoe\/' + uid + '\/' + str(execution_id) + '/d' #pylint: disable=anomalous-backslash-in-string
135
        docker_client = docker.Client(base_url=get_conf().proxy_docker_sock)
hxquangnhat's avatar
hxquangnhat committed
136
137
138
        del_command = 'sed -i "' + pattern + '" ' + get_conf().proxy_config_file #  /etc/apache2/sites-available/all.conf'
        del_id = docker_client.exec_create(get_conf().proxy_container, del_command)
        docker_client.exec_start(del_id)