Skip to content

Commit f964d09

Browse files
authored
CLOUDP-61571: Add Basic Dev Scripts (#40)
1 parent 43370a2 commit f964d09

20 files changed

+447
-38
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,5 @@ tags
7878

7979
.idea
8080
vendor
81-
zz_generated*.go
81+
zz_generated*.go
82+
__pycache__
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
kind: ClusterRoleBinding
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
metadata:
4+
name: test-runner
5+
subjects:
6+
- kind: ServiceAccount
7+
name: test-runner
8+
namespace: default
9+
roleRef:
10+
kind: ClusterRole
11+
name: cluster-admin # TODO: create cluster role with only required permissions
12+
apiGroup: rbac.authorization.k8s.io

deploy/testrunner/role.yaml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,3 @@ rules:
8080
- patch
8181
- update
8282
- watch
83-
84-
---
85-
kind: ClusterRole
86-
apiVersion: rbac.authorization.k8s.io/v1
87-
metadata:
88-
name: test-runner
89-
rules:
90-
- apiGroups:
91-
- '*'
92-
resources:
93-
- '*'
94-
verbs:
95-
- '*'
96-
- nonResourceURLs:
97-
- '*'
98-
verbs:
99-
- '*'

deploy/testrunner/role_binding.yaml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,3 @@ roleRef:
99
kind: Role
1010
name: test-runner
1111
apiGroup: rbac.authorization.k8s.io
12-
13-
---
14-
kind: ClusterRoleBinding
15-
apiVersion: rbac.authorization.k8s.io/v1
16-
metadata:
17-
name: test-runner
18-
roleRef:
19-
apiGroup: rbac.authorization.k8s.io
20-
kind: ClusterRole
21-
name: test-runner
22-
subjects:
23-
- kind: ServiceAccount
24-
name: test-runner
25-
namespace: default

docker/requirements.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

scripts/ci/build_and_push_image.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
echo ${quay_password} | docker login -u=${quay_user_name} quay.io --password-stdin
44

5-
python docker/dockerfile_generator.py ${image_type} > Dockerfile
5+
python scripts/dev/dockerfile_generator.py ${image_type} > Dockerfile
66
docker build . -f Dockerfile -t ${image}
77
docker push ${image}

scripts/ci/run_unit_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/sh
22

3-
python docker/dockerfile_generator.py "unittest" > Dockerfile
3+
python scripts/dev/dockerfile_generator.py "unittest" > Dockerfile
44
docker build . -f Dockerfile -t unit-tests:${version_id}
55
docker run unit-tests:${version_id}

scripts/dev/__init__.py

Whitespace-only changes.
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from dockerutil import build_and_push_image
2+
from dockerfile_generator import render
3+
from kubernetes import client, config
4+
from kubernetes.client.rest import ApiException
5+
from dev_config import DevConfig, load_config
6+
from typing import Dict, Optional
7+
import yaml
8+
import io
9+
import os
10+
import time
11+
12+
13+
def _load_operator_service_account() -> Optional[Dict]:
14+
return load_yaml_from_file("deploy/service_account.yaml")
15+
16+
17+
def _load_operator_role() -> Optional[Dict]:
18+
return load_yaml_from_file("deploy/role.yaml")
19+
20+
21+
def _load_operator_role_binding() -> Optional[Dict]:
22+
return load_yaml_from_file("deploy/role_binding.yaml")
23+
24+
25+
def _load_operator_deployment() -> Optional[Dict]:
26+
return load_yaml_from_file("deploy/operator.yaml")
27+
28+
29+
def _load_mongodb_crd() -> Optional[Dict]:
30+
return load_yaml_from_file("deploy/crds/mongodb.com_mongodbs_crd.yaml")
31+
32+
33+
def load_yaml_from_file(path: str) -> Optional[Dict]:
34+
with open(path, "r") as f:
35+
return yaml.full_load(f.read())
36+
return None
37+
38+
39+
def _ensure_crds():
40+
"""
41+
ensure_crds makes sure that all the required CRDs have been created
42+
"""
43+
crdv1 = client.ApiextensionsV1beta1Api()
44+
crd = _load_mongodb_crd()
45+
46+
ignore_if_doesnt_exist(
47+
lambda: crdv1.delete_custom_resource_definition("mongodbs.mongodb.com")
48+
)
49+
50+
# TODO: fix this, when calling create_custom_resource_definition, we get the error
51+
# ValueError("Invalid value for `conditions`, must not be `None`")
52+
# but the crd is still successfully created
53+
try:
54+
crdv1.create_custom_resource_definition(body=crd)
55+
except ValueError as e:
56+
pass
57+
58+
print("Ensured CRDs")
59+
60+
61+
def build_and_push_operator(repo_url: str, tag: str, path: str):
62+
"""
63+
build_and_push_operator creates the Dockerfile for the operator
64+
and pushes it to the target repo
65+
"""
66+
return build_and_push_image(repo_url, tag, path, "operator")
67+
68+
69+
def _ignore_error_codes(fn, codes):
70+
try:
71+
fn()
72+
except ApiException as e:
73+
if e.status not in codes:
74+
raise
75+
76+
77+
def ignore_if_already_exists(fn):
78+
"""
79+
ignore_if_already_exists accepts a function and calls it,
80+
ignoring an Kubernetes API conflict errors
81+
"""
82+
83+
return _ignore_error_codes(fn, [409])
84+
85+
86+
def ignore_if_doesnt_exist(fn):
87+
"""
88+
ignore_if_doesnt_exist accepts a function and calls it,
89+
ignoring an Kubernetes API not found errors
90+
"""
91+
return _ignore_error_codes(fn, [404])
92+
93+
94+
def deploy_operator():
95+
"""
96+
deploy_operator ensures the CRDs are created, and als creates all the required ServiceAccounts, Roles
97+
and RoleBindings for the operator, and then creates the operator deployment.
98+
"""
99+
appsv1 = client.AppsV1Api()
100+
corev1 = client.CoreV1Api()
101+
rbacv1 = client.RbacAuthorizationV1Api()
102+
103+
dev_config = load_config()
104+
_ensure_crds()
105+
106+
ignore_if_already_exists(
107+
lambda: rbacv1.create_namespaced_role(
108+
dev_config.namespace, _load_operator_role()
109+
)
110+
)
111+
ignore_if_already_exists(
112+
lambda: rbacv1.create_namespaced_role_binding(
113+
dev_config.namespace, _load_operator_role_binding()
114+
)
115+
)
116+
ignore_if_already_exists(
117+
lambda: corev1.create_namespaced_service_account(
118+
dev_config.namespace, _load_operator_service_account()
119+
)
120+
)
121+
ignore_if_already_exists(
122+
lambda: appsv1.create_namespaced_deployment(
123+
dev_config.namespace, _load_operator_deployment()
124+
)
125+
)
126+
127+
128+
def main():
129+
config.load_kube_config()
130+
dev_config = load_config()
131+
build_and_push_operator(
132+
dev_config.repo_url, f"{dev_config.repo_url}/mongodb-kubernetes-operator", "."
133+
)
134+
deploy_operator()
135+
136+
137+
if __name__ == "__main__":
138+
main()

scripts/dev/dev_config.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from typing import Dict, Optional
2+
import json
3+
import os
4+
5+
CONFIG_PATH = "~/.community-operator-dev/config.json"
6+
FULL_CONFIG_PATH = os.path.expanduser(CONFIG_PATH)
7+
8+
9+
class DevConfig:
10+
"""
11+
DevConfig is a wrapper around the developer configuration file
12+
"""
13+
14+
def __init__(self, config):
15+
self._config = config
16+
17+
@property
18+
def namespace(self):
19+
return self._config["namespace"]
20+
21+
@property
22+
def repo_url(self):
23+
return self._config["repo_url"]
24+
25+
26+
def load_config() -> Optional[DevConfig]:
27+
with open(FULL_CONFIG_PATH, "r") as f:
28+
return DevConfig(json.loads(f.read()))
29+
30+
print(
31+
f"No DevConfig found. Please ensure that the configuration file exists at '{FULL_CONFIG_PATH}'"
32+
)
33+
return None

0 commit comments

Comments
 (0)