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

Working async POC!!! #19

Merged
merged 12 commits into from
Jun 28, 2018
Merged

Working async POC!!! #19

merged 12 commits into from
Jun 28, 2018

Conversation

grafuls
Copy link
Owner

@grafuls grafuls commented Jun 24, 2018

💥 An example implementation of a working POC with async/await implementation.

@grafuls grafuls added this to the POC milestone Jun 24, 2018
@grafuls grafuls requested review from jan-zmeskal and ILpinto June 24, 2018 21:04
@grafuls grafuls changed the title Working async POC!!! 💥 Working async POC!!! Jun 24, 2018
@grafuls grafuls changed the title 💥 Working async POC!!! Working async POC!!! Jun 24, 2018
@@ -2,13 +2,13 @@
- disrupt_action:
- name: Kill services on VM start
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see it for testing - change name for "Kill .." to testing ping to file or something like that.

async def run_client(self, filepath, expression, timeout):
async with await asyncssh.connect(self.hostname) as conn:
logger.debug("Connected to %s", self.hostname)
stdin, stdout, stderr = await conn.open_session("tail -f %s" % filepath)
Copy link
Collaborator

Choose a reason for hiding this comment

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

tail -f will put all the log to the memory, and if we have file rotate it will not work,
maybe try:
tail -F | grep --line-buffered -A 3 -B 5
Or tail -F | grep -C 5

Copy link
Owner Author

Choose a reason for hiding this comment

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

The receive buffers are cleared everytime we read from stdout.
https://groups.google.com/d/topic/asyncssh-users/i1ouhyekxt8/discussion

Change-Id: I34b4aaf2636bfcaee1ee8299bff048ba4376409a
@grafuls
Copy link
Owner Author

grafuls commented Jun 25, 2018

#6

Change-Id: I54f7b01f103627d266dad00dc93faa19d04ad3ef
Copy link
Collaborator

@jan-zmeskal jan-zmeskal left a comment

Choose a reason for hiding this comment

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

Unfortunately I have not had enough time to go through it all properly nor actually execute it. I skimmed through the cli.py mostly, se the review is far from complete. But we are still in early development stage, so we might go back and change things easily if need be.



@click.command()
def main(args=None):
@click.option(
"--experiments-path",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Potential technical debt here described in #24. No need to tackle it the moment thogh.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Agree. We could add an additional option like --experiment.



@click.command()
def main(args=None):
@click.option(
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's probably an argument why experiments-path should be an argument instead of option. The reasoning has two points:

  1. There's no point in running disruption_generator without this. Options usually just modify behaviour of the program, while executing disruption_generator without experiments-path makes no sense.
  2. The help string IMO makes more sense then:
    Usage: disruption_generator [OPTIONS] [EXPERIMENTS_PATH]

Copy link
Owner Author

Choose a reason for hiding this comment

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

It's been implemented as an option since not providing this argument during execution will default to ./experiments (in the context of the execution). We can reconsider removing this and requesting the experiment path as mandatory.

@@ -16,6 +16,7 @@ Sphinx = "==1.7.1"
twine = "==1.10.0"
pytest = "==3.4.2"
pytest-runner = "==2.11.1"
pytest-asyncio = "*"
Copy link
Collaborator

Choose a reason for hiding this comment

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

ipdb? :-)

Copy link
Owner Author

Choose a reason for hiding this comment

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

Don't want to impose a debugger in case contributors prefer others. 🌎

"-e",
type=click.Path(exists=True, file_okay=False, readable=True, resolve_path=True),
help="Path to experiments yamls",
default="./experiments/",
Copy link
Collaborator

Choose a reason for hiding this comment

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

This implies that you're in specific path when executing disruption_generator, which is not necessarily the case. I am thinking if this default path can't be made relative to the location of this module?

for (dirpath, dirnames, filenames) in walk(experiments_path):
for file in filenames:
_files.append(path.join(dirpath, file))
break # Get's only root level directory files
Copy link
Collaborator

Choose a reason for hiding this comment

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

Delete '

Copy link
Owner Author

Choose a reason for hiding this comment

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

done

break # Get's only root level directory files
_scenarios = []
for _file in _files:
_parser = ExperimentParser(yaml_path=_file)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Honestly I am not a huge fan of prefixing var names with '_' unless there's very good reason for it. Sometimes it's a good idea because the var name might e.g. mirror built-in name. Or you want to say everybody not to touch that specific piece of code. But I cannot think of why we should use it here.

Copy link
Owner Author

Choose a reason for hiding this comment

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

from [1]:
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member).

[1] https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

async def execute(experiments_path):
_files = []
for (dirpath, dirnames, filenames) in walk(experiments_path):
for file in filenames:
Copy link
Collaborator

Choose a reason for hiding this comment

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

This mirrors python2 built-in: https://docs.python.org/2/library/functions.html#file It's okay since we're using python3, but I would still rename it to f, that's common python convention

Copy link
Owner Author

Choose a reason for hiding this comment

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

Good point, forgot to prefix with _

yield disruption
_disruptions.append(disruption)

return _disruptions
Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking that maybe we could call here scenario as well since we call it like that in main method. I don't really mind why var name we use and I am not gonna argue about variable names. But labeling the same thing with the same name at different places really makes it easier for contributors to visually parse a program.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Speaking of which, it seems to me that it would me a lot of sense to create Scenario class that would be collection of Disruptions, if that is the intent.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Agree on refactoring to scenario. No need for a Scenario class at the moment since there is no additional metadata related to it. We can consider it in the future if necessary.

_scenarios.extend(scenario)
for scenario in _scenarios:
click.echo("Scenario: %s" % scenario)
alistener = Alistener(scenario.listener.target)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have to say that is's a bit confusing that scenario variable (which holds Disruption object in this case) has listener attribute which is something completely different than Alistener. Listener class just holds some text data so I suppose it could be called differently.

alistener = Alistener(scenario.listener.target)

for action in scenario.actions:
result = await alistener.tail(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please let's generally use this format: result = await alistener.tail(filepath=scenario.listener.log, expression=scenario.listener.re, timeout=action.timeout). Once again it really helps to quickly parse it visually.

grafuls added 2 commits June 26, 2018 15:49
Change-Id: I10a21489604f4702ce83f90bcf37d7c6106ce47b
@@ -7,6 +7,7 @@ class Action(object):
"""
A trigger object with the requested disruptive action.
"""

name = attr.ib(validator=attr.validators.instance_of(six.text_type))
Copy link
Owner Author

Choose a reason for hiding this comment

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

consider removing six since we are not using python2

@grafuls grafuls self-assigned this Jun 28, 2018
@grafuls grafuls added the enhancement New feature or request label Jun 28, 2018
@grafuls grafuls merged commit 039d7d7 into master Jun 28, 2018
@grafuls grafuls deleted the alistener branch June 28, 2018 13:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants