Example #1
0
 def _get_rook_files(self):
     # TODO (bleon)
     # This is not optima. Need to retrieve RPM directly and extract files
     # out of it. RPM URL should be configurable
     execute(f"rsync -avr -e 'ssh -i {self.workspace.private_key}'"
             f" sles@{self.kubernetes.hardware.masters[0].get_ssh_ip()}"
             f":/usr/share/k8s-yaml/rook {self.workspace.working_dir}")
Example #2
0
    def _cloud_init_seed_create(self):
        user_data = textwrap.dedent("""
            #cloud-config
            debug: True
            ssh_authorized_keys:
                - {}
        """)
        meta_data = textwrap.dedent("""
            ---
            instance-id: {}
            local-hostname: {}
        """)

        iso_cmd = shutil.which('mkisofs')
        if not iso_cmd:
            raise Exception('mkisofs command not found')

        if os.path.exists(self._cloud_init_seed_path):
            os.remove(self._cloud_init_seed_path)
        with tempfile.TemporaryDirectory() as tempdir:
            with open(os.path.join(tempdir, 'user-data'), 'w') as ud:
                ud.write(user_data.format(self._ssh_public_key))
            with open(os.path.join(tempdir, 'meta-data'), 'w') as md:
                md.write(meta_data.format(uuid.uuid4(), self.name))
            # create the seed file
            args = [
                iso_cmd, '-output', self._cloud_init_seed_path, '-volid',
                'cidata', '-joliet', '-rock', tempdir
            ]
            execute(" ".join(args), log_stdout=False, log_stderr=False)
Example #3
0
 def _backing_file_create(self):
     if os.path.exists(self._snap_img_path):
         logger.info(f"node {self.name}: Delete available backing image "
                     f"{self._snap_img_path}")
         os.remove(self._snap_img_path)
     execute(f"qemu-img create -f qcow2 -F qcow2 -o "
             f"backing_file={self._image_path} {self._snap_img_path} 10G")
     logger.info(f"node {self.name}: created qcow2 backing file under"
                 f"{self._snap_img_path}")
Example #4
0
 def get_rook(self):
     logger.info("Clone rook version %s from repo %s" % (
         settings.UPSTREAM_ROOK.VERSION,
         settings.UPSTREAM_ROOK.REPO))
     execute(
         "git clone -b %s %s %s" % (
             settings.UPSTREAM_ROOK.VERSION,
             settings.UPSTREAM_ROOK.REPO,
             self.build_dir),
         log_stderr=False
     )
Example #5
0
    def get_rook(self):
        if not converter('@bool', settings.UPSTREAM_ROOK.BUILD_ROOK_FROM_GIT):
            return

        super().get_rook()
        logger.info(
            "Clone rook version %s from repo %s" %
            (settings.UPSTREAM_ROOK.VERSION, settings.UPSTREAM_ROOK.REPO))
        execute("git clone -b %s %s %s" %
                (settings.UPSTREAM_ROOK.VERSION, settings.UPSTREAM_ROOK.REPO,
                 self.build_dir),
                log_stderr=False)
Example #6
0
 def _get_rook_yaml(self):
     # do not use rpm-package for self-built rook images
     if converter('@bool', settings.SES.BUILD_ROOK_FROM_GIT):
         self.ceph_dir = os.path.join(
             self.build_dir, 'cluster/examples/kubernetes/ceph')
         return
     # TODO (bleon)
     # This is not optima. Need to retrieve RPM directly and extract files
     # out of it. RPM URL should be configurable
     execute(f"rsync -avr -e 'ssh -i {self.workspace.private_key}'"
             f" {settings.NODE_IMAGE_USER}"
             f"@{self.kubernetes.hardware.masters[0].get_ssh_ip()}"
             f":/usr/share/k8s-yaml/rook {self.workspace.working_dir}")
Example #7
0
 def disk_create(self, capacity):
     """
     Create a disk volume
     """
     super().disk_create(capacity)
     capacity_gb = f"{capacity}G"
     suffix = ''.join(
         random.choice(string.ascii_lowercase) for i in range(5))
     name = f"{self._name}-volume-{suffix}"
     disk_path = os.path.join(self._workspace.working_dir, f"{name}.qcow2")
     execute(f"qemu-img create -f qcow2 {disk_path} {capacity_gb}")
     self._disks[name] = {'path': disk_path, 'attached': False, 'xml': None}
     logger.info(f"disk {name} created")
     return name
Example #8
0
    def execute(
        self,
        command: str,
        capture: bool = False,
        check: bool = True,
        log_stdout: bool = True,
        log_stderr: bool = True,
        env: Optional[Dict[str, str]] = None,
        logger_name: Optional[str] = None,
        chdir: Optional[str] = None
    ) -> Tuple[int, Optional[str], Optional[str]]:
        """Executes a command inside the workspace

        This is a wrapper around the execute util that will automatically
        chdir into the workspace and set some common env vars (such as the
        ssh agent).
        """
        if not env:
            env = {
                'PATH': os.environ.get('PATH', '/usr/local/bin:/usr/bin:/bin')
            }
        env['PATH'] = f"{os.path.join(self.working_dir, 'bin')}:{env['PATH']}"
        with self.chdir(chdir):
            env['SSH_AUTH_SOCK'] = self.ssh_agent_auth_sock
            env['SSH_AGENT_PID'] = self.ssh_agent_pid
            return execute(command,
                           capture=capture,
                           check=check,
                           log_stdout=log_stdout,
                           log_stderr=log_stderr,
                           env=env,
                           logger_name=logger_name)
Example #9
0
def _check_docker_requirement():
    logger.debug("Checking if docker is running...")
    if settings.DISTRO == 'openSUSE_k8s' and \
            converter('@bool', settings.UPSTREAM_ROOK.BUILD_ROOK_FROM_GIT):
        rc, out, err = common.execute('docker ps', log_stdout=False)
        if rc != 0:
            raise Exception("Docker is not running - see manual.")
        logger.debug("... Docker appears to be ready")
Example #10
0
 def add_data_disk(self, capacity='10G'):
     _id = len(self._disks) + 2  # one for root disk, one for cloud-init
     volume_name = f'data-{_id}'
     block_device = f'vd{string.ascii_lowercase[_id + 1]}'
     disk_path = os.path.join(self._workspace.working_dir,
                              f"{self.name}-{volume_name}.qcow2")
     execute(f"qemu-img create -f qcow2 {disk_path} {capacity}")
     logger.info(f'Created volume "{volume_name}" / size={capacity}')
     disk = textwrap.dedent("""
         <disk type='file' device='disk'>
             <driver name='qemu' type='qcow2' cache='none'/>
             <source file='%(disk_path)s'/>
             <target dev='%(block_device)s' bus='virtio'/>
         </disk>
     """ % {
         "disk_path": disk_path,
         "block_device": block_device
     })
     self._dom.attachDevice(disk)
     self._disks.append(disk_path)
Example #11
0
    def build(self):
        super().build()
        self.get_rook()
        if not converter('@bool', settings.UPSTREAM_ROOK.BUILD_ROOK_FROM_GIT):
            return

        self.get_golang()
        logger.info("Compiling rook...")
        execute(
            command=f"make --directory {self.build_dir} "
                    f"-j BUILD_REGISTRY='rook-build' IMAGES='ceph'",
            env={"PATH": f"{self.workspace.bin_dir}/go/bin:"
                         f"{os.environ['PATH']}",
                 "TMPDIR": self.workspace.tmp_dir,
                 "GOCACHE": self.workspace.tmp_dir,
                 "GOPATH": self.workspace.build_dir},
            log_stderr=False)

        image = 'rook/ceph'
        tag = f"{settings.UPSTREAM_ROOK.VERSION}-rookcheck"
        self.rook_image = f"{image}:{tag}"
        logger.info(f"Tag image as {image}:{tag}")
        execute(f'docker tag "rook-build/ceph-amd64" {image}:{tag}')

        logger.info("Save image tar")
        # TODO(jhesketh): build arch may differ
        execute(f"docker save {image}:{tag} | gzip > %s"
                % os.path.join(self.build_dir, 'rook-ceph.tar.gz'))
        self._rook_built = True
 def kubectl(self, command, check=True, log_stdout=True, log_stderr=True):
     """
     Run a kubectl command
     """
     return common.execute(
         f"{self.kubectl_exec} --kubeconfig {self.kubeconfig}"
         f" {command}",
         check=check,
         capture=True,
         log_stdout=log_stdout,
         log_stderr=log_stderr,
         logger_name=f"kubectl {command}",
     )
 def helm(self, command, check=True, log_stdout=True, log_stderr=True):
     """
     Run a helm command
     """
     return common.execute(
         f"{self.helm_exec} --kubeconfig {self.kubeconfig}"
         f" {command}",
         check=check,
         capture=True,
         log_stdout=log_stdout,
         log_stderr=log_stderr,
         logger_name=f"helm {command}",
         env={'HELM_EXPERIMENTAL_OCI': '1'},
     )
Example #14
0
    def _ssh_agent(self):
        try:
            # NOTE(jhesketh): We can't use self.execute yet because
            #                 self.ssh_agent_pid is not ready yet.
            rc, stdout, stderr = execute(
                f'ssh-agent -a {self.ssh_agent_auth_sock}', capture=True)
        except subprocess.CalledProcessError:
            logger.exception('Failed to start ssh agent')
            raise

        self._ssh_agent_pid = stdout.split(';')[2].split('=')[1]
        try:
            logging.info("Adding ssh-key to agent")
            # NOTE(jhesketh): For some reason, ssh-add outputs to stderr which
            #                 will be logged as a warning. It's not really
            #                 dangerous because we're creating and destroying
            #                 our own agent, so we'll suppress the messages.
            self.execute(f'ssh-add {self.private_key}', log_stderr=False)
        except subprocess.CalledProcessError:
            logger.exception('Failed to add keys to agent')
            raise
Example #15
0
    def build(self):
        self.get_rook()

        self.get_golang()
        logger.info("Compiling rook...")
        execute(
            command=f"make --directory {self.build_dir} "
                    f"-j BUILD_REGISTRY='rook-build' IMAGES='ceph'",
            env={"PATH": f"{self.workspace.bin_dir}/go/bin:"
                         f"{os.environ['PATH']}",
                 "TMPDIR": self.workspace.tmp_dir,
                 "GOCACHE": self.workspace.tmp_dir,
                 "GOPATH": self.workspace.build_dir},
            log_stderr=False)

        logger.info(f"Tag image as {self.rook_image}")
        execute(f'docker tag "rook-build/ceph-amd64" {self.rook_image}')

        logger.info("Save image tar")
        # TODO(jhesketh): build arch may differ
        execute(f"docker save {self.rook_image} | gzip > %s"
                % os.path.join(self.build_dir, 'rook-ceph.tar.gz'))
        self._rook_built = True
Example #16
0
    def build_rook(self):
        logger.info("[build_rook] Download go")
        wget.download(
            "https://dl.google.com/go/go1.13.9.linux-amd64.tar.gz",
            os.path.join(self.builddir, 'go-amd64.tar.gz'),
            bar=None,
        )

        logger.info("[build_rook] Unpack go")
        execute(
            "tar -C %s -xzf %s" %
            (self.builddir, os.path.join(self.builddir, 'go-amd64.tar.gz')))

        # TODO(jhesketh): Allow setting rook version
        logger.info("[build_rook] Checkout rook")
        execute("mkdir -p %s" %
                os.path.join(self.builddir, 'src/github.com/rook/rook'))
        execute("git clone https://github.com/rook/rook.git %s" %
                os.path.join(self.builddir, 'src/github.com/rook/rook'),
                log_stderr=False)
        # TODO(jhesketh): Allow testing various versions of rook
        execute("pushd %s && git checkout v1.3.1 && popd" %
                os.path.join(self.builddir, 'src/github.com/rook/rook'),
                log_stderr=False)

        logger.info("[build_rook] Make rook")
        execute(
            "PATH={builddir}/go/bin:$PATH GOPATH={builddir} "
            "make --directory='{builddir}/src/github.com/rook/rook' "
            "-j BUILD_REGISTRY='rook-build' IMAGES='ceph' "
            "build".format(builddir=self.builddir),
            log_stderr=False,
            logger_name="make -j BUILD_REGISTRY='rook-build' IMAGES='ceph'",
        )

        logger.info("[build_rook] Tag image")
        execute('docker tag "rook-build/ceph-amd64" rook/ceph:master')

        logger.info("[build_rook] Save image tar")
        # TODO(jhesketh): build arch may differ
        execute("docker save rook/ceph:master | gzip > %s" %
                os.path.join(self.builddir, 'rook-ceph.tar.gz'))

        self.ceph_dir = os.path.join(
            self.builddir,
            'src/github.com/rook/rook/cluster/examples/kubernetes/ceph')

        self._rook_built = True
Example #17
0
def test_command_matrix(log_stdout, log_stderr, capture, check, fail_command,
                        logger_name, caplog):
    # Capturing behaves differently depending if logging is enabled or an error
    # is raised, so test with a complete matrix of log_stdout/err.

    # Force caplog to INFO level so that we get what we expect
    caplog.set_level(logging.INFO)

    cmd = 'echo "Hello world" && >&2 echo "error"'
    expected_rc = 0
    if fail_command:
        expected_rc = 30
        cmd += f" && exit {expected_rc}"

    try:
        rc, stdout, stderr = execute(cmd,
                                     capture=capture,
                                     log_stdout=log_stdout,
                                     log_stderr=log_stderr,
                                     check=check,
                                     logger_name=logger_name)
    except subprocess.CalledProcessError as exception:
        if check:
            # We have to get the return values from the exception
            rc = exception.returncode
            stdout = exception.stdout
            stderr = exception.stderr
        else:
            assert False, "No error should have been raised with check=False!"

    assert rc == expected_rc
    if capture:
        assert stdout == "Hello world\n"
        assert stderr == "error\n"
    else:
        assert stdout is None
        assert stderr is None

    logger_name_check = logger_name if logger_name is not None else cmd

    if log_stdout and log_stderr:
        assert len(caplog.records) == 2
        for record in caplog.records:
            if record.levelname == 'INFO':
                assert record.name == logger_name_check
                assert record.levelname == 'INFO'
                assert record.getMessage() == 'Hello world'
            else:
                assert record.name == logger_name_check
                assert record.levelname == 'WARNING'
                assert record.getMessage() == 'error'
    elif log_stdout:
        assert len(caplog.records) == 1
        assert caplog.records[0].name == logger_name_check
        assert caplog.records[0].levelname == 'INFO'
        assert caplog.records[0].getMessage() == 'Hello world'
    elif log_stderr:
        assert len(caplog.records) == 1
        assert caplog.records[0].name == logger_name_check
        assert caplog.records[0].levelname == 'WARNING'
        assert caplog.records[0].getMessage() == 'error'
Example #18
0
def test_command_env():
    rc, stdout, stderr = execute("echo $MYVAR",
                                 env={'MYVAR': "Hello world"},
                                 capture=True)
    assert stdout == "Hello world\n"
    assert stderr == ""