Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/sonobuoy integration #819

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a326e99
Enable compliance tests to use plugins for cluster provisioning
tonifinger Sep 18, 2024
ab0803b
Fix python style
tonifinger Sep 18, 2024
199fdf2
Fix path to junit file
tonifinger Sep 20, 2024
f994cde
Inital integration of the plugin into the 'scs-test-runner.py'
tonifinger Oct 7, 2024
4a51c0d
Adjust 'scs-test-runner.py' to handle kaas tests
tonifinger Oct 10, 2024
928ea83
Add ability to deploy clusters for different K8s versions
tonifinger Oct 14, 2024
acc451d
Update `scs-test-runner.py`
tonifinger Oct 18, 2024
e4d6c3c
still draft: a few steps towards my vision
mbuechse Oct 23, 2024
1dd220c
add missing file
mbuechse Oct 23, 2024
7c063d8
Fixup!
tonifinger Oct 23, 2024
5b11641
Fixup plugin kubeconfig file generation
tonifinger Oct 24, 2024
7fb5f32
Draft: split up clusterspec file
tonifinger Nov 4, 2024
9a2809a
Merge to back to usage of one single clustersspec
tonifinger Nov 4, 2024
bfa6ba4
Rearange configuration files
tonifinger Nov 5, 2024
1cfee94
Fixup configuration files
tonifinger Nov 5, 2024
9f7fe4c
Fixup configuration files
tonifinger Nov 5, 2024
3e5357a
revert sonobuoy executor handling form this PR
tonifinger Nov 5, 2024
99c450f
Apply cluster configuration file handling
tonifinger Nov 5, 2024
5adb9f6
Update Tests/kaas/plugin/run_plugin.py
tonifinger Nov 5, 2024
2127323
Update Tests/config.toml
tonifinger Nov 5, 2024
5392c5e
Fixup
tonifinger Nov 5, 2024
73edf99
Restructure abstract method handling in plugin
tonifinger Nov 6, 2024
90d958e
Add example plugin implementation to interface.py
tonifinger Nov 6, 2024
fc78a7c
Fixup: change kube_plugin_config directory name
tonifinger Nov 6, 2024
76134d6
Fixup: missing adjustment to config.toml
tonifinger Nov 6, 2024
cfa113c
Remove abstract base clase handling and directly
tonifinger Nov 7, 2024
d43a38d
Update 'kind_plugin.py' kubeconfig filepath handling
tonifinger Nov 7, 2024
8f4970b
Sort python imports
tonifinger Nov 7, 2024
5a8f8ca
Fixup: use '__name__' for logging handler
tonifinger Nov 7, 2024
7d6a0cb
Update Tests/kaas/plugin/run_plugin.py
tonifinger Nov 7, 2024
c4b2611
Update plugin kubeconfig handling
tonifinger Nov 7, 2024
78fd694
Update plugin_static.py
tonifinger Nov 7, 2024
2301ba3
Fixup remove obsolete f-string
tonifinger Nov 7, 2024
fa0247e
Fixup
tonifinger Nov 8, 2024
932ed7a
Fixup: remove default value in description
tonifinger Nov 8, 2024
a96047d
Fixup: remove version parameter form delete
tonifinger Nov 11, 2024
c686a45
Merge branch 'main' into 710-feature-request-enable-compliance-tests-…
tonifinger Nov 18, 2024
6cab484
Fixup plugin deletion parameters
tonifinger Nov 19, 2024
e3f0932
Inital sonobuoy integration
tonifinger Nov 13, 2024
d97a5d9
Fixup:
tonifinger Nov 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion Tests/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,51 @@ subjects = [
workers = 4


[presets.all-kaas]
scopes = [
"scs-compatible-kaas",
]
subjects = [
"cspA-current",
"cspA-current-1",
"cspA-current-2",
]
workers = 4


[scopes.scs-compatible-iaas]
spec = "./scs-compatible-iaas.yaml"


[scopes.scs-compatible-kaas]
spec = "./scs-compatible-kaas.yaml"


# default subject (not a real subject, but used to declare a default mapping)
# (this is the only mapping declaration that supports using Python string interpolation)
[subjects._.mapping]
os_cloud = "{subject}"
os_cloud = "{subject}"
subject_root = "{subject}"


[subjects._.kubernetes_setup]
clusterspec = "kaas/clusterspec.yaml"


[subjects.cspA-current.kubernetes_setup]
kube_plugin = "kind"
kube_plugin_config = "../playbooks/k8s_configs/kind_config.yaml"
clusterspec_cluster = "current-k8s-release"


[subjects.cspA-current-1.kubernetes_setup]
kube_plugin = "kind"
kube_plugin_config = "../playbooks/k8s_configs/kind_config.yaml"
clusterspec_cluster = "current-k8s-release-1"


[subjects.cspA-current-2.kubernetes_setup]
kube_plugin = "kind"
kube_plugin_config = "../playbooks/k8s_configs/kind_config.yaml"
clusterspec_cluster = "current-k8s-release-2"

11 changes: 11 additions & 0 deletions Tests/kaas/clusterspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# this file specifies all clusters that have to be provisioned for the tests to run
clusters:
current-k8s-release:
branch: "1.31"
kubeconfig: kubeconfig.yaml
current-k8s-release-1:
branch: "1.30"
kubeconfig: kubeconfig.yaml
current-k8s-release-2:
branch: "1.29"
kubeconfig: kubeconfig.yaml
39 changes: 39 additions & 0 deletions Tests/kaas/plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Plugin for provisioning k8s clusters and performing conformance tests on these clusters

## Development environment

### requirements

* [docker](https://docs.docker.com/engine/install/)
* [kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
* [sonobuoy](https://sonobuoy.io/docs/v0.57.1/#installation)

### setup for development

1. Generate python 3.10 env

```bash
sudo apt-get install python3.10-dev
virtualenv -p /usr/bin/python3.10 venv
echo "*" >> venv/.gitignore
source venv/bin/activate
(venv) curl -sS https://bootstrap.pypa.io/get-pip.py | python3.10
(venv) python3.10 -m pip install --upgrade pip
(venv) python3.10 -m pip --version

```

2. Install dependencies:

```bash
(venv) pip install pip-tools
(venv) pip-compile requirements.in
(venv) pip-sync requirements.txt
```

3. Set environment variables and launch the process:

```bash
(venv) export CLUSTER_PROVIDER="kind"
(venv) python run.py
```
54 changes: 54 additions & 0 deletions Tests/kaas/plugin/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@


class KubernetesClusterPlugin():
"""
An abstract base class for custom Kubernetes cluster provider plugins.
It represents an interface class from which the api provider-specific
plugins must be derived as child classes

To implement fill the methods `create_cluster` and `delete_cluster` with
api provider-specific functionalities for creating and deleting clusters.
The `create_cluster` method must ensure that the kubeconfigfile is provided
at the position in the file system defined by the parameter
`kubeconfig_filepath`

- Implement `create_cluster` and `delete_cluster` methods
- Create `__init__(self, config_file)` method to handle api specific
configurations.

Example:
.. code:: python

from interface import KubernetesClusterPlugin
from apiX_library import cluster_api_class as ClusterAPI

class PluginX(KubernetesClusterPlugin):

def __init__(self, config_file):
self.config = config_file

def create_cluster(self, cluster_name, version, kubeconfig_filepath):
self.cluster = ClusterAPI(name=cluster_name, image=cluster_image, kubeconfig_filepath)
self.cluster.create(self.config)

def delete_cluster(self, cluster_name):
self.cluster = ClusterAPI(cluster_name)
self.cluster.delete()
..
"""

def create_cluster(self, cluster_name, version, kubeconfig_filepath):
"""
This method is to be called to create a k8s cluster
:param: cluster_name:
:param: version:
:param: kubeconfig_filepath:
"""
raise NotImplementedError

def delete_cluster(self, cluster_name):
"""
This method is to be called in order to unprovision a cluster
:param: cluster_name:
"""
raise NotImplementedError
50 changes: 50 additions & 0 deletions Tests/kaas/plugin/plugin_kind.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import logging
import os
import os.path
from pathlib import Path

from interface import KubernetesClusterPlugin
from pytest_kind import KindCluster

logger = logging.getLogger(__name__)


class PluginKind(KubernetesClusterPlugin):
"""
Plugin to handle the provisioning of kubernetes cluster for
conformance testing purpose with the use of Kind
"""
def __init__(self, config_file):
logger.info("Init PluginKind")
self.config = config_file
logger.debug(self.config)
self.working_directory = os.getcwd()
logger.debug(f"Working from {self.working_directory}")

def create_cluster(self, cluster_name, version, kubeconfig):
"""
This method is to be called to create a k8s cluster
:param: kubernetes_version:
:return: kubeconfig_filepath
"""
cluster_version = version
if cluster_version == '1.29':
cluster_version = 'v1.29.8'
elif cluster_version == '1.30':
cluster_version = 'v1.30.4'
elif cluster_version == '1.31' or cluster_version == 'default':
cluster_version = 'v1.31.1'
cluster_image = f"kindest/node:{cluster_version}"
kubeconfig_filepath = Path(kubeconfig)
if kubeconfig_filepath is None:
raise ValueError("kubeconfig_filepath is missing")
else:
self.cluster = KindCluster(name=cluster_name, image=cluster_image, kubeconfig=kubeconfig_filepath)
if self.config is None:
self.cluster.create()
else:
self.cluster.create(self.config)

def delete_cluster(self, cluster_name):
self.cluster = KindCluster(cluster_name)
self.cluster.delete()
19 changes: 19 additions & 0 deletions Tests/kaas/plugin/plugin_static.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import shutil

from interface import KubernetesClusterPlugin


class PluginStatic(KubernetesClusterPlugin):
"""
Plugin to handle the provisioning of kubernetes
using a kubeconfig file
"""

def __init__(self, config_file):
self.kubeconfig_path = config_file

def create_cluster(self, cluster_name, version, kubeconfig):
shutil.copyfile(self.kubeconfig_path, kubeconfig)

def delete_cluster(self, cluster_name, version):
pass
3 changes: 3 additions & 0 deletions Tests/kaas/plugin/requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest-kind
kubernetes
junitparser
62 changes: 62 additions & 0 deletions Tests/kaas/plugin/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements.in
#
cachetools==5.5.0
# via google-auth
certifi==2024.8.30
# via
# kubernetes
# requests
charset-normalizer==3.3.2
# via requests
google-auth==2.34.0
# via kubernetes
idna==3.8
# via requests
junitparser==3.2.0
# via -r requirements.in
kubernetes==30.1.0
# via -r requirements.in
oauthlib==3.2.2
# via
# kubernetes
# requests-oauthlib
pyasn1==0.6.0
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.0
# via google-auth
pykube-ng==23.6.0
# via pytest-kind
pytest-kind==22.11.1
# via -r requirements.in
python-dateutil==2.9.0.post0
# via kubernetes
pyyaml==6.0.2
# via
# kubernetes
# pykube-ng
requests==2.32.3
# via
# kubernetes
# pykube-ng
# requests-oauthlib
requests-oauthlib==2.0.0
# via kubernetes
rsa==4.9
# via google-auth
six==1.16.0
# via
# kubernetes
# python-dateutil
urllib3==2.2.2
# via
# kubernetes
# pykube-ng
# requests
websocket-client==1.8.0
# via kubernetes
60 changes: 60 additions & 0 deletions Tests/kaas/plugin/run_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python3
import logging
import os.path

import click
import yaml

from plugin_kind import PluginKind
from plugin_static import PluginStatic

PLUGIN_LOOKUP = {
"kind": PluginKind,
"static": PluginStatic,
}


def init_plugin(plugin_kind, config=None):
plugin_maker = PLUGIN_LOOKUP.get(plugin_kind)
if plugin_maker is None:
raise ValueError(f"unknown plugin '{plugin_kind}'")
return plugin_maker(config)


def load_spec(clusterspec_path):
with open(clusterspec_path, "rb") as fileobj:
return yaml.load(fileobj, Loader=yaml.SafeLoader)


@click.group()
def cli():
pass


@cli.command()
@click.argument('plugin_kind', type=click.Choice(list(PLUGIN_LOOKUP), case_sensitive=False))
@click.argument('plugin_config', type=click.Path(exists=True, dir_okay=False))
@click.argument('clusterspec_path', type=click.Path(exists=True, dir_okay=False))
@click.argument('clusterspec_cluster', type=str, default="default")
def create(plugin_kind, plugin_config, clusterspec_path, clusterspec_cluster):
clusterspec = load_spec(clusterspec_path)['clusters']
plugin = init_plugin(plugin_kind, plugin_config)
clusterinfo = clusterspec[clusterspec_cluster]
cluster_id = clusterspec_cluster
plugin.create_cluster(cluster_id, clusterinfo['branch'], os.path.abspath(clusterinfo['kubeconfig']))


@cli.command()
@click.argument('plugin_kind', type=click.Choice(list(PLUGIN_LOOKUP), case_sensitive=False))
@click.argument('plugin_config', type=click.Path(exists=True, dir_okay=False))
@click.argument('clusterspec_path', type=click.Path(exists=True, dir_okay=False))
@click.argument('clusterspec_cluster', type=str, default="default")
def delete(plugin_kind, plugin_config, clusterspec_path, clusterspec_cluster):
cluster_id = clusterspec_cluster
plugin = init_plugin(plugin_kind, plugin_config)
plugin.delete_cluster(cluster_id)


if __name__ == '__main__':
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
cli()
26 changes: 26 additions & 0 deletions Tests/kaas/sonobuoy_handler/run_sonobuoy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
# vim: set ts=4 sw=4 et:
#

from sonobuoy_handler import SonobuoyHandler
import sys
import click
import logging

logger = logging.getLogger(__name__)


@click.command()
@click.option("-k", "--kubeconfig", "kubeconfig", type=click.Path(exists=False), default=None, help="path/to/kubeconfig_file.yaml",)
@click.option("-r", "--result_dir_name", "result_dir_name", type=str, default="sonobuoy_results", help="directory name to store results at",)
@click.option("-c", "--check", "check_name", type=str, default="sonobuoy_executor", help="this MUST be the same name as the id in 'scs-compatible-kaas.yaml'",)
@click.option("-a", "--arg", "args", multiple=True)
def sonobuoy_run(kubeconfig, result_dir_name, check_name, args):
logger.info("Run sonobuoy_executor")
sonobuoy_handler = SonobuoyHandler(check_name, kubeconfig, result_dir_name, args)
return_code = sonobuoy_handler.run()
sys.exit(return_code)


if __name__ == "__main__":
sonobuoy_run()
Loading