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

Feature/ch 87 #710

Merged
merged 3 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
49 changes: 36 additions & 13 deletions tools/deployment-cli-tools/ch_cli_tools/skaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json
import time

from os.path import join, dirname, relpath, basename
from os.path import join, relpath, basename, exists, abspath
from cloudharness_model import ApplicationTestConfig, HarnessMainConfig

from cloudharness_utils.constants import APPS_PATH, DEPLOYMENT_CONFIGURATION_PATH, \
Expand Down Expand Up @@ -51,7 +51,7 @@ def build_artifact(image_name, context_path, requirements=None, dockerfile_path=
in requirements]
return artifact_spec


base_images = set()

def process_build_dockerfile(dockerfile_path, root_path, global_context=False, requirements=None, app_name=None):
Expand All @@ -78,21 +78,21 @@ def process_build_dockerfile(dockerfile_path, root_path, global_context=False, r

for dockerfile_path in base_dockerfiles:
process_build_dockerfile(dockerfile_path, root_path, global_context=True)


release_config = skaffold_conf['deploy']['helm']['releases'][0]
release_config['name'] = helm_values.namespace
release_config['namespace'] = helm_values.namespace
release_config['artifactOverrides'][KEY_APPS] = {}

static_images = set()
for root_path in root_paths:
static_dockerfiles = find_dockerfiles_paths(
join(root_path, STATIC_IMAGES_PATH))

for dockerfile_path in static_dockerfiles:
process_build_dockerfile(dockerfile_path, root_path)


for root_path in root_paths:
apps_path = join(root_path, APPS_PATH)
Expand Down Expand Up @@ -138,22 +138,45 @@ def process_build_dockerfile(dockerfile_path, root_path, global_context=False, r
}
}

flask_main = find_file_paths(context_path, '__main__.py')

if flask_main:
mains_candidates = find_file_paths(context_path, '__main__.py')

def identify_unicorn_based_main(candidates):
import re
gunicorn_pattern = re.compile(r"gunicorn")
for candidate in candidates:
dockerfile_path = f"{candidate}/.."
while not exists(f"{dockerfile_path}/Dockerfile") and abspath(dockerfile_path) != abspath(root_path):
dockerfile_path += "/.."
dockerfile = f"{dockerfile_path}/Dockerfile"
if not exists(dockerfile):
continue
with open(dockerfile, 'r') as file:
if re.search(gunicorn_pattern, file.read()):
return candidate
requirements = f"{candidate}/../requirements.txt"
if not exists(requirements):
continue
with open(requirements, 'r') as file:
if re.search(gunicorn_pattern, file.read()):
return candidate
return None

task_main_file = identify_unicorn_based_main(mains_candidates)

if task_main_file:
release_config['overrides']['apps'][app_key] = \
{
'harness': {
'deployment': {
'command': ['python'],
'args': [f'/usr/src/app/{os.path.basename(flask_main[0])}/__main__.py']
'args': [f'/usr/src/app/{os.path.basename(task_main_file)}/__main__.py']
}
}
}

test_config: ApplicationTestConfig = helm_values.apps[app_key].harness.test
if test_config.unit.enabled and test_config.unit.commands:

skaffold_conf['test'].append(dict(
image=get_image_tag(app_name),
custom=[dict(command="docker run $IMAGE " + cmd) for cmd in test_config.unit.commands]
Expand Down Expand Up @@ -209,7 +232,7 @@ def get_image_tag(name):
"/usr/src/app"),
}
})


if not os.path.exists(os.path.dirname(vscode_launch_path)):
os.makedirs(os.path.dirname(vscode_launch_path))
Expand Down
22 changes: 22 additions & 0 deletions tools/deployment-cli-tools/tests/resources_buggy/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
**/node_modules
.tox
docs
applications
/infrastructure
/blueprint
test
/tools/deployment-cli-tools
.github
.git
.vscode
/deployment
skaffold.yaml
*.egg-info
__pycache__
.hypothesis
.coverage
.pytest_cache
/application-templates
/deployment-configuration
/cloud-harness
.openapi-generator
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kafka:
resources:
limits:
cpu: overridden-prod
requests:
cpu: 50m
memory: 100Mi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kafka:
resources:
limits:
cpu: 600m
memory: overridden
requests:
cpu: 50m
memory: 100Mi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.ignored
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ARG CLOUDHARNESS_FLASK
FROM $CLOUDHARNESS_FLASK

RUN pip install gunicorn
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
harness:
name: "I'm useless"
subdomain: mysubdomain
dependencies:
soft:
- legacy
build:
- cloudharness-flask
- my-common
a: b
dev: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a: test
test: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
harness:
database:
auto: true
type: mongo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
harness:
database: {auto: true, type: postgres}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
harness:
name: "I'm useless"
subdomain: mysubdomain
dependencies:
soft:
- legacy
build:
- cloudharness-flask
test:
unit:
commands:
- tox
- echo "hello"
a: b
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python3

from cloudharness.utils.server import init_flask, main


app = init_flask(title="Cloudharness sample application", webapp=True)

if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env python3

from something import something_else


def fake_content():
...
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.ignored
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ARG CLOUDHARNESS_FLASK
FROM $CLOUDHARNESS_FLASK

RUN pip install -r requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
harness:
name: "I'm useless"
subdomain: mysubdomain
dependencies:
soft:
- legacy
build:
- cloudharness-flask
- my-common
a: b
dev: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a: test
test: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
harness:
database:
auto: true
type: mongo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
harness:
database: {auto: true, type: postgres}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
harness:
name: "I'm useless"
subdomain: mysubdomain
dependencies:
soft:
- legacy
build:
- cloudharness-flask
test:
unit:
commands:
- tox
- echo "hello"
a: b
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python3

from cloudharness.utils.server import init_flask, main


app = init_flask(title="Cloudharness sample application", webapp=True)

if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gunicorn
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env python3

from something import something_else


def fake_content():
...
75 changes: 74 additions & 1 deletion tools/deployment-cli-tools/tests/test_skaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

HERE = os.path.dirname(os.path.realpath(__file__))
RESOURCES = os.path.join(HERE, 'resources')
RESOURCES_BUGGY = os.path.join(HERE, 'resources_buggy')
OUT = '/tmp/deployment'
CLOUDHARNESS_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))

Expand Down Expand Up @@ -70,7 +71,7 @@ def test_create_skaffold_configuration():
a for a in sk['build']['artifacts'] if a['image'] == 'reg/cloudharness/cloudharness-flask')


assert os.path.samefile(cloudharness_flask_artifact['context'],
assert os.path.samefile(cloudharness_flask_artifact['context'],
join(CLOUDHARNESS_ROOT, 'infrastructure/common-images/cloudharness-flask')
)

Expand Down Expand Up @@ -102,3 +103,75 @@ def test_create_skaffold_configuration():

shutil.rmtree(OUT)
shutil.rmtree(BUILD_DIR)


def test_create_skaffold_configuration_with_conflicting_dependencies(tmp_path):
values = create_helm_chart(
[CLOUDHARNESS_ROOT, RESOURCES_BUGGY],
output_path=OUT,
include=['myapp'],
exclude=['events'],
domain="my.local",
namespace='test',
env='dev',
local=False,
tag=1,
registry='reg'
)
root_paths = preprocess_build_overrides(
root_paths=[CLOUDHARNESS_ROOT, RESOURCES_BUGGY],
helm_values=values,
merge_build_path=str(tmp_path)
)

sk = create_skaffold_configuration(
root_paths=root_paths,
helm_values=values,
output_path=OUT
)

releases = sk['deploy']['helm']['releases']
assert len(releases) == 1 # Ensure we only found 1 deployment (for myapp)

release = releases[0]
assert 'myapp' in release['overrides']['apps']
assert 'matplotlib' not in release['overrides']['apps']

myapp_config = release['overrides']['apps']['myapp']
assert myapp_config['harness']['deployment']['args'][0] == '/usr/src/app/myapp_code/__main__.py'


def test_create_skaffold_configuration_with_conflicting_dependencies_requirements_file(tmp_path):
values = create_helm_chart(
[CLOUDHARNESS_ROOT, RESOURCES_BUGGY],
output_path=OUT,
include=['myapp2'],
exclude=['events'],
domain="my.local",
namespace='test',
env='dev',
local=False,
tag=1,
registry='reg'
)
root_paths = preprocess_build_overrides(
root_paths=[CLOUDHARNESS_ROOT, RESOURCES_BUGGY],
helm_values=values,
merge_build_path=str(tmp_path)
)

sk = create_skaffold_configuration(
root_paths=root_paths,
helm_values=values,
output_path=OUT
)

releases = sk['deploy']['helm']['releases']
assert len(releases) == 1 # Ensure we only found 1 deployment (for myapp)

release = releases[0]
assert 'myapp2' in release['overrides']['apps']
assert 'matplotlib' not in release['overrides']['apps']

myapp_config = release['overrides']['apps']['myapp2']
assert myapp_config['harness']['deployment']['args'][0] == '/usr/src/app/myapp_code/__main__.py'
Loading