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

Refactor plugins #76

Merged
merged 8 commits into from Jul 11, 2018
Merged

Refactor plugins #76

merged 8 commits into from Jul 11, 2018

Conversation

jmaupetit
Copy link
Contributor

@jmaupetit jmaupetit commented Jul 6, 2018

Purpose

Current "plugins" implementation is far from academic. We should follow Ansible's recommendations to improve them.

Proposal

  • Switch the app lookup call to a real lookup plugin
  • Fix merge filter implementation (remove deepmerge and make our own)
  • Add tests for plugins
  • Automate tests execution in the CI
  • Add python code linters (pylint, flake8, isort)

@jmaupetit jmaupetit self-assigned this Jul 6, 2018
@jmaupetit jmaupetit force-pushed the refactor-plugins branch 5 times, most recently from 1044434 to 6079b08 Compare July 10, 2018 15:09
@jmaupetit jmaupetit changed the title WIP: refactor plugins Refactor plugins Jul 10, 2018
@@ -47,16 +55,17 @@ jobs:
bin/build
mkdir -p /tmp/docker/images
docker save -o /tmp/docker/images/arnold.tar "${ARNOLD_IMAGE}"
# Store the built as an artifact that can be reused in other jobs
# Save built to the workspace so that it can be reused in other jobs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/built/build?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant save the built to the workspace.

- *docker_load
- run: bin/lint plugins

test-built:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/built/build?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test the build 😉

@@ -105,22 +129,54 @@ jobs:
"${ARNOLD_IMAGE}" \
ansible --version

# FIXME: we have deactivated plugins test coverage as the container user is
# not allowed to write to /app/.coverage and CircleCI does not allowed to
# mount volumes with "docker run" commands.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're saying this and then below you're mounting /app/.pytest_cache?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a classical volume it's a tmpfs. Concerning volumes, I think I cannot use them since we are in "dind" mode. We need to switch to the machine executor at least for this task.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why can't you use a tmpfs for /app/.coverage also?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's a file, not a directory.

@@ -105,22 +129,54 @@ jobs:
"${ARNOLD_IMAGE}" \
ansible --version

# FIXME: we have deactivated plugins test coverage as the container user is
# not allowed to write to /app/.coverage and CircleCI does not allowed to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/allowed/allow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 it's the container user that is not allowed to

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I nearly apologized... then I realized that there are 2 "allowed" in this sentence ^^

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. you're right.

- lint-plugins:
requires:
- build
- test-built:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok... maybe you really meant built instead of build...

assert deep_sort_dict(d) == expected

def test_deep_embedded_dict(self):
"""Avoid testing recursivity"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong docstring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Sorry for that.

"bar": ["a", "b", "c", "d"],
}

assert deep_sort_dict(d) == expected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should add:

assert d == {
"foo": {"baz": [4, 1, 6, {"lol": ["x", "z", "y"]}]},
"bar": ["c", "b", "d", "a"],
}

Same on all tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not if we test immutability separately?

maxDiff = None

def assertDictDeepEqual(self, a, b):
"""Use a sorted json string to deep compare apps (dictionaries)"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring seems wrong. Here you are testing that they are pointing to the same reference, not that their json representation is the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow. I should have carefully check my docstring. This is an old dumb implementation.

)

def test_submitted_apps_name_is_not_empty(self):
"""Submitted apps should have the same ``name`` key"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy/paste fail


def test_services_merge_with_empty_new_services(self):
"""
Test app services merge with no services or volumes for tje new
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/tje/the


def test_services_merge_without_duplicates(self):
"""
Test app services merge does not creates duplicates if same items
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/creates/create

"name": "baz",
"configs": ["baz.conf"],
"templates": ["baz/dc.yml", "baz/svc.yml", "baz/ep.yml"],
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the fun service is gone is it what you expect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we take data from right (new) to left (base) if the app is defined in left (base), i.e. you cannot define a new app that is not listed as available (with files in apps/).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the moment I just read the tests. Maybe it deserves a line in the docstring.
Then the concept could be explained in some documentation (in another PR is fine)?

Instead of using the pipe lookup with an executed python program output,
we implemented our own lookup plugin. It should have already been this
way from the start.
Following Ansible's guidelines, this work adds a fully fonctionnal test
environment using pytest.
d = {"foo": 1, "bar": ["c", "b", "d", "a"]}
s = deep_sort_dict(d)

assert d != s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertion is good but you didn't test that it does not modify d :-)
assert d == {"foo": 1, "bar": ["c", "b", "d", "a"]} ?

│   │   ├── dc.yml.j2
│   │   └── svc.yml.j2
│   ├── nginx
│   │   ├── _configs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think singular is better: config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see plural everywhere (volumes, templates, etc). Let's stick to it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but config is "the config"? Pick what you prefer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be more that once configuration for a service (e.g. edxapp cms + lms ngnix configurations).

"""Merge data from the "new" application to the "base" application"""
"""
Merge data from the "new" application to the "base" application.
Services listed in "new" that does not exist in "base" will be ignored.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/does/do

for k in ("configs", "templates"):
if new_service.get(k) is None:
continue
base_service[k] = sorted(list(set(new_service[k] + base_service[k])))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add a comment to explain that you do list(set( to deduplicate?

Switch to our own apps merge implementation to avoid duplicates in
lists.
The merge_with_app filter reliability is a core part of the app
discovery feature. It requires intense testing to ensure consistency of
our whole strategy.
A cosmetic update to make job names more homogeneous in FUN's projects.
We now run unit tests of Arnold's plugins in the CI.
We now use pylint, isort and flake8 to lint our custom plugins.
Unfortunately black cannot be used as we are running python 2.7 and it
requires at least python 3.6.
* apply black-style formatting
* fix flake8 and isort warnings
@jmaupetit jmaupetit merged commit 4d2f0b4 into master Jul 11, 2018
@jmaupetit jmaupetit deleted the refactor-plugins branch July 11, 2018 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants