Ejemplo n.º 1
0
    def __init__(self, config_file='~/.ficloud.yml'):
        self.ficloud_yml = expanduser(config_file)

        # load config
        if os.path.exists(self.ficloud_yml):
            with open(self.ficloud_yml) as f:
                self.config = yaml.load(f)
                if self.config is None:
                    self.config = {}
        else:
            self.config = {}

        if 'host' in self.config:
            env.host_string = self.config['host']

        env.output_prefix = False
        fabric.state.output.running = False

        self.client = Client()

        self.project_dir = None
        self.project_name = None
        self.env_name = None
        self._project = None
Ejemplo n.º 2
0
 def setUpClass(cls):
     cls.client = Client(docker_url())
     cls.client.pull('ubuntu', tag='latest')
Ejemplo n.º 3
0
 def setUpClass(cls):
     cls.client = Client(docker_url())
     cls.client.pull('busybox', tag='latest')
Ejemplo n.º 4
0
class FicloudDeployment():
    def __init__(self, config_file='~/.ficloud.yml'):
        self.ficloud_yml = expanduser(config_file)

        # load config
        if os.path.exists(self.ficloud_yml):
            with open(self.ficloud_yml) as f:
                self.config = yaml.load(f)
                if self.config is None:
                    self.config = {}
        else:
            self.config = {}

        if 'host' in self.config:
            env.host_string = self.config['host']

        env.output_prefix = False
        fabric.state.output.running = False

        self.client = Client()

        self.project_dir = None
        self.project_name = None
        self.env_name = None
        self._project = None

    def init(self, project_dir, env_name, project_name=None):
        self.project_dir = project_dir
        self.env_name = env_name

        if not project_name:
            project_name = project_name_by_dir()

        self.project_name = project_name


    def _get_fig_project(self):

        if not self.env_name:
            raise ValueError('env is not specified!')

        if not self.project_dir:
            raise ValueError('project_dir is not specified!')

        if not self.project_name:
            raise ValueError('project_name is not specified!')

        os.chdir(self.project_dir)
        with open('ficloud.yml') as f:
            config = yaml.load(f)

        config = transform_config(config['services'], env=self.env_name)
        project = Project.from_config(self.project_name, config, self.client)
        return project

    @property
    def host(self):
        if not 'host' in self.config:
            raise ValueError('host is not selected!')
        return self.config['host']

    @property
    def project(self):
        if not self._project:
            self._project = self._get_fig_project()
        return self._project

    def use_host(self, host, **kwargs):
        """
        Sets currently used host
        """
        self.config['host'] = host
        env.host_string = host

        self.save_config()

    def pull_volumes(self, volumes, **kwargs):
        return self.push_volumes(volumes, reverse=True, **kwargs)

    def push_volumes(self, volumes, reverse=False, **kwargs):
        for volume in volumes:

            p = re.compile(r'^([\w\-]+):([\w\d/_-]+)@([\w\-]+)#([\w\-]+)$')
            result = p.match(volume)

            if not result:
                print('\nVolume should be of format service:/volume/path@app#version')
                return

            (service, volume_name, app, version) = result.groups()

            data = run('ficloud-server app %s %s volumes --json' % (app, version))
            data = json.loads(data)

            volume_key = '%s@%s' % (service, volume_name)

            if not volume_key in data:
                ValueError('Remote volume %s not found on remote server' % volume_name)

            local_data = self.get_volumes()
            if not volume_key in local_data:
                ValueError('Remote volume %s not found on local machine' % volume_name)

            # reverse = pull operation
            if reverse:
                (data, local_data) = (local_data, data)

            cmd = 'sudo rsync -e "ssh -i /home/%(user)s/.ssh/id_rsa" --delete -vv -r -p --numeric-ids -e ssh' \
                  ' --rsync-path="sudo rsync" %(local_path)s/ %(host_string)s:%(remote_path)s' % {
                      'user': getpass.getuser(),
                      'host_string': env.host_string,
                      'local_path': local_data[volume_key],
                      'remote_path': data[volume_key]
                  }

            os.system(cmd)


    def status(self, **kwargs):

        table = PrettyTable(["Service", "Status"])

        for service in self.project.services:
            table.add_row((service.name, format_service_status(service)))

        print(table)

    def run(self, service, command, **kwargs):

        service = self.project.get_service(service)

        container = service.create_container(one_off=True, **{
            'command': command,
            'tty': True,
            'stdin_open': True,
        })

        with self._attach_to_container(container.id, raw=True) as c:
            service.start_container(container, ports=None)
            c.run()

    def _attach_to_container(self, container_id, raw=False):
        socket_in = self.client.attach_socket(container_id, params={'stdin': 1, 'stream': 1})
        socket_out = self.client.attach_socket(container_id, params={'stdout': 1, 'logs': 1, 'stream': 1})
        socket_err = self.client.attach_socket(container_id, params={'stderr': 1, 'logs': 1, 'stream': 1})

        return SocketClient(
            socket_in=socket_in,
            socket_out=socket_out,
            socket_err=socket_err,
            raw=raw,
        )

    def start(self, services=None, logs=True, rebuild=False, **kwargs):

        project = self.project

        if rebuild:
            project.stop(services)
            project.remove_stopped(services)
            project.build(services)

        all_containers = []
        for service in project.get_services(services):
            if len(service.containers(stopped=True)) == 0:
                service.create_container()

            all_containers += service.containers(stopped=True)

        log_printer = None
        if logs:
            log_printer = LogPrinter(all_containers)

        project.start(services)

        if log_printer:
            try:
                print("Following logs from containers.")
                log_printer.run()
            except KeyboardInterrupt:
                print("Interrupted by Ctrl + C. Containers are still running. Use `ficloud stop` to stop them.")


    def stop(self, services=None, **kwargs):
        project = self.project
        project.stop(services)

    def destroy(self, services=None, **kwargs):
        project = self.project
        project.stop(services)
        project.kill(services)
        project.remove_stopped(services)

    def rebuild(self, services=None, **kwargs):
        self.start(services, rebuild=True)

    def logs(self, services=None, **kwargs):
        project = self.project

        containers = project.containers(service_names=services, stopped=True)
        LogPrinter(containers, attach_params={'logs': True}).run()

    def get_volumes(self, **kwargs):
        volumes = {}
        for service in self.project.get_services():

            for c in service.containers(stopped=True):
                for volume, dir in c.inspect()['Volumes'].items():
                    volumes['%s@%s' % (service.name, volume)] = dir
        return volumes

    def list_volumes(self, **kwargs):

        if kwargs['json']:
            print(json.dumps(self.get_volumes()))
            return

        table = PrettyTable(["Volume", "Mount directory"])
        for volume, dir in self.get_volumes().items():
            table.add_row((
                volume,
                dir
            ))

        print(table)


    def remote(self, command, **kwargs):
        run('ficloud-server %s' % ' '.join(command))


    def save_config(self):
        with open(self.ficloud_yml, 'w+') as f:
            yaml.dump(self.config, f)