예제 #1
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def validate_volumes(self):
        """
            Check if the volumes we have are valid.
            Additionally, expand stuff like ~
        """

        if not bool(self.volumes):
            return

        for v in list(self.volumes):
            console.debug(
                f'processing plan [cyan]{self.name}[/] volume [bold]{v}[/]')

            if 'bind' not in self.volumes[v]:
                console.warn(
                    f'plan [cyan]{self.name}[/] volume [bold]{v}[/] does not have a bind'
                )
                self.valid = False
                return

            nv = str(Path(v).expanduser().resolve())
            console.debug(
                f'normalised plan [cyan]{self.name}[/] host volume [bold]{v}[/] is [bold]{nv}[/]'
            )
            self.volumes[nv] = self.volumes.pop(v)
예제 #2
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def run(self) -> models.containers.Container:
        """
            Run the containers for a plan
        """

        self._ensure_net_exists()
        self._ensure_image_exists()  # inline dockerfiles
        console.debug(
            f'starting service container [bold]{self.get_container_name()}[/]'
            f' for plan [bold]{self.plan.name}[/]')

        opts = self.plan.run_options()
        opts['name'] = self.get_container_name()

        container = self.get_client(). \
            containers.run(self.plan.image_version(), network=config.net_name(), **opts)

        if not self.plan.exposed_ports:
            return container

        for port_map in self.plan.exposed_ports:
            inside, outside = port_map[0], port_map[1]
            self.run_net(outside, inside)

        return container
예제 #3
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def _ensure_net_exists(self):
        """
            Ensures that the network image and docker network exists.
        """

        try:
            self.get_client().images.get(config.net_container_name())
            self.get_client().networks.get(config.net_name())
        except ImageNotFound as _:
            console.info(
                f'network image [bold]{config.net_container_name()}[/] does not exist, quickly building it'
            )
            _, logs = self.get_client().images.build(
                path=str(NETWORK_CONTAINER_PATH),
                pull=True,
                tag=config.net_container_name(),
                rm=True,
                forcerm=True)

            for log in logs:
                console.debug(log)

            console.info(
                f'network container [bold]{config.net_container_name()}[/] built'
            )
            self._ensure_net_exists()

        except NotFound as _:
            console.info(
                f'docker network [bold]{config.net_name()}[/] does not exist, creating it'
            )
            self.get_client().networks.create(name=config.net_name(),
                                              check_duplicate=True)
            self._ensure_net_exists()
예제 #4
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def add_commands(self, c: Union[str, list]):
        """
            Adds a command to the plan

            :param c:
            :return:
        """

        console.debug(f'adding commands {c} to plan {self.name}')
        self.command = self.command + ' ' + ' '.join(c)
예제 #5
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def load_dist_plans(self):
        """
            Load .yml files from the plans/ directory

        """

        for p in DIST_PLAN_DIRECTORY.glob('**/*.yml'):
            console.debug(f'processing dist plan [bold]{p}[/]')

            with p.open() as f:
                d = yaml.load(f, Loader=yaml.SafeLoader)

            p = Plan(p)
            p.from_dict(d)

            self.plans.append(p)
예제 #6
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def stop(self):
        """
            Stops containers
        """

        for container in self.containers():
            console.debug(
                f'stopping container [bold]{container.name}[/] for plan [cyan]{self.plan.name}[/]'
            )
            try:
                container.stop()
            except NotFound as _:
                # if the container is not found, it may already be gone (exited?)
                pass
            except Exception as e:
                console.warn(
                    f'failed to stop container with error [dim]{type(e)}[/]: [bold]{e}[/]'
                )
예제 #7
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def run_net(self, outside: int, inside: int):
        """
            Run a network container for a plan
        """

        self._ensure_net_exists()

        console.debug(
            f'starting network proxy [green]{inside}[/]<-{self.get_container_name()}<-'
            f'[red]{outside}[/] for plan [bold]{self.plan.name}[/]')

        self.get_client(). \
            containers.run(config.net_container_name(), detach=True,
                           environment={
                               'REMOTE_HOST': self.get_container_name(),
                               'REMOTE_PORT': inside, 'LOCAL_PORT': outside,
                           }, stderr=True, stdout=True, remove=True,
                           network=config.net_name(), ports={outside: outside},
                           name=self.get_net_container_name_with_ports(outside, inside))
예제 #8
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def populate_ports(self):
        """
            Translates the ports property to a list of
            tuples in the exposed_ports property.
        """

        if not self.ports:
            return

        if isinstance(self.ports, int):
            console.debug(
                f'adding plan [cyan]{self.name}[/] port map for single '
                f'port: [bold]{self.ports}<-{self.ports}[/]')
            self.exposed_ports.append((self.ports, self.ports))
            return

        if isinstance(self.ports, dict):
            for inside, outside in self.ports.items():
                console.debug(
                    f'adding plan [cyan]{self.name}[/] port map for port '
                    f'pair [bold]{inside}<-{outside}[/]')
                self.exposed_ports.append((inside, outside))
                return

        # if we got a list, recursively validate & map
        if isinstance(self.ports, list):
            console.debug(
                f'processing plan [cyan]{self.name}[/] port map list '
                f'({self.ports}) recursively')
            o = self.ports
            for mapping in o:
                self.ports = mapping
                self.populate_ports()
예제 #9
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def load_user_plans(self):
        """
            Load .yml files from the ~/.dwn/plans directory

            :return:
        """

        for p in USER_PLAN_DIRECTORY.glob('**/*.yml'):
            console.debug(f'processing plan [bold]{p}[/]')

            with p.open() as f:
                d = yaml.load(f, Loader=yaml.SafeLoader)

            if not d:
                continue

            if self.get_plan(d['name'], valid_only=False):
                console.debug(
                    f'possible duplicate plan called {d["name"]} from {p}')

            p = Plan(p)
            p.from_dict(d)

            self.plans.append(p)
예제 #10
0
파일: network.py 프로젝트: yashomer1994/dwn
def build_container():
    """
        Builds the network container
    """

    console.info('building network container')

    try:
        client = docker.from_env()
    except DockerException as e:
        console.error(f'docker client failed: [bold]{e}[/]')
        return

    console.debug(f'path to docker context is: [bold]{NETWORK_CONTAINER_PATH}[/]')
    console.debug(f'network container will be called [bold]\'{config.net_container_name()}\'[/]')

    image, logs = client.images.build(
        path=str(NETWORK_CONTAINER_PATH), pull=True, tag=config.net_container_name())

    for log in logs:
        console.debug(log)

    console.info(f'network container \'{config.net_container_name()}\' built')
예제 #11
0
파일: plan.py 프로젝트: yashomer1994/dwn
    def _ensure_image_exists(self):
        """
            Ensures that an image exists if a plan has an inline
            dockerfile.
        """

        # if the plan does not have an inline dockerfile, then we can rely on
        # the call to run() later to pull the image instead.
        if not self.plan.has_dockerfile():
            return

        console.debug(f'checking if {self.plan.image_version()} is available')

        try:
            self.get_client().images.get(self.plan.image_version())
        except ImageNotFound as _:
            console.warn(
                f'image for plan [cyan]{self.plan.name}[/] does not exist, quickly building it'
            )

            dockerfile = BytesIO(self.plan.dockerfile.encode('utf-8'))
            console.debug(f'building dockerfile:\n{self.plan.dockerfile}')

            _, logs = self.get_client().images.build(
                fileobj=dockerfile,
                pull=True,
                tag=self.plan.image_version(),
                rm=True,
                forcerm=True)

            for log in logs:
                console.debug(log)

            console.info(
                f'container for [bold]{self.plan.image_version()}[/] built')
            self._ensure_net_exists()
예제 #12
0
파일: plans.py 프로젝트: vcont/dwn
def update(name):
    """
        Update plan images.
    """

    plan_targets = []

    if not name and not click.confirm('> a plan name was not specified, '
                                      'pull all valid plan images?'):
        return

    try:
        client = docker.from_env()
    except DockerException as e:
        console.error(f'failed to connect to docker: [bold]{e}[/e]')
        return

    loader = Loader()

    if name:
        plan_targets.append(loader.get_plan(name))
    else:
        [plan_targets.append(n) for n in loader.valid_plans()]

    for p in plan_targets:
        if p is None:
            continue

        try:
            # build the image if we have an inline dockerfile
            if p.has_dockerfile():
                console.info(f'building image [bold]{p.image_version()}[/]')
                dockerfile = BytesIO(p.dockerfile.encode('utf-8'))

                _, logs = client.images.build(fileobj=dockerfile,
                                              pull=True,
                                              tag=p.image_version(),
                                              rm=True,
                                              forcerm=True,
                                              nocache=True)
                for log in logs:
                    console.debug(log)

                console.info(
                    f'container for [bold]{p.image_version()}[/] built')

            # pull the image instead
            else:
                console.info(f'pulling image [bold]{p.image_version()}[/]')
                client.images.pull(p.image, tag=p.version)

        except ImageNotFound as e:
            console.error(f'failed to pull image: [bold]{e}[/]')
            continue
        except DockerException as e:
            console.error(f'a docker exception occurred: [bold]{e}[/]')
            continue

        console.info(
            f'image [bold]{p.image_version()}[/] for plan [cyan]{p.name}[/] updated'
        )