-
Notifications
You must be signed in to change notification settings - Fork 4
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
Conversation
@@ -2,13 +2,13 @@ | |||
- disrupt_action: | |||
- name: Kill services on VM start |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
Change-Id: I54f7b01f103627d266dad00dc93faa19d04ad3ef
There was a problem hiding this 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", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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:
- There's no point in running
disruption_generator
without this. Options usually just modify behaviour of the program, while executingdisruption_generator
withoutexperiments-path
makes no sense. - The help string IMO makes more sense then:
Usage: disruption_generator [OPTIONS] [EXPERIMENTS_PATH]
There was a problem hiding this comment.
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 = "*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ipdb? :-)
There was a problem hiding this comment.
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. 🌎
disruption_generator/cli.py
Outdated
"-e", | ||
type=click.Path(exists=True, file_okay=False, readable=True, resolve_path=True), | ||
help="Path to experiments yamls", | ||
default="./experiments/", |
There was a problem hiding this comment.
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?
disruption_generator/cli.py
Outdated
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delete '
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
disruption_generator/cli.py
Outdated
break # Get's only root level directory files | ||
_scenarios = [] | ||
for _file in _files: | ||
_parser = ExperimentParser(yaml_path=_file) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
disruption_generator/cli.py
Outdated
async def execute(experiments_path): | ||
_files = [] | ||
for (dirpath, dirnames, filenames) in walk(experiments_path): | ||
for file in filenames: |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
disruption_generator/cli.py
Outdated
_scenarios.extend(scenario) | ||
for scenario in _scenarios: | ||
click.echo("Scenario: %s" % scenario) | ||
alistener = Alistener(scenario.listener.target) |
There was a problem hiding this comment.
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.
disruption_generator/cli.py
Outdated
alistener = Alistener(scenario.listener.target) | ||
|
||
for action in scenario.actions: | ||
result = await alistener.tail( |
There was a problem hiding this comment.
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.
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)) |
There was a problem hiding this comment.
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
💥 An example implementation of a working POC with async/await implementation.