{"id":13533570,"url":"https://github.com/gremlin/gremlin-python","last_synced_at":"2026-03-10T18:03:43.328Z","repository":{"id":37929629,"uuid":"243851375","full_name":"gremlin/gremlin-python","owner":"gremlin","description":"A Python SDK for the Gremlin API","archived":false,"fork":false,"pushed_at":"2024-04-08T16:28:45.000Z","size":595,"stargazers_count":65,"open_issues_count":2,"forks_count":13,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-03-05T16:18:49.779Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gremlin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-28T20:45:07.000Z","updated_at":"2025-01-20T06:25:05.000Z","dependencies_parsed_at":"2024-11-06T05:03:02.759Z","dependency_job_id":null,"html_url":"https://github.com/gremlin/gremlin-python","commit_stats":{"total_commits":609,"total_committers":13,"mean_commits":46.84615384615385,"dds":0.4022988505747126,"last_synced_commit":"e006c6864def9c3a0face85b21d44ea26e9d360f"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gremlin%2Fgremlin-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gremlin%2Fgremlin-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gremlin%2Fgremlin-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gremlin%2Fgremlin-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gremlin","download_url":"https://codeload.github.com/gremlin/gremlin-python/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246713477,"owners_count":20821895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:01:21.079Z","updated_at":"2025-12-13T18:29:00.476Z","avatar_url":"https://github.com/gremlin.png","language":"Python","readme":"# gremlin-python\n\n![](https://github.com/gremlin/gremlin-python/raw/master/Gremlin_Python_Icon.png?raw=true)\n\n## Project Status\nThis is an unoffical PythonSDK currently in alpha testing. \n\n## Installation\n\n### PyPi\n\n```bash\npip3 install gremlinapi\n```\n\n### Install from source\n\n```bash\ngit clone git@github.com:gremlin/gremlin-python.git\ncd gremlin-python\npython3 setup.py install\n```\n\n### Use Packaged Docker runtime\n\nBuild and run this project's self contained docker image with all the necessary dependencies\n```shell script\n  make docker-build \u0026\u0026 make docker-run-interactive\n```\n\n## Usage\n\n### CLI\n\nComing soon\n\n## Authenticate to the API\n\nThe Gremlin API requires a form of authentication, either API Key or Bearer Token. API Keys are the least privileged\nform of authentication, are easy to manage and change, but do not allow for company wide actions \n[see https://www.gremlin.com/docs/api-reference/overview/](https://www.gremlin.com/docs/api-reference/overview/) for\na list of which API endpoints support API Keys vs. Bearer Tokens.\n\nA bearer token may be provided to the API instead of an API Key, and this allow the owner of the bearer token to use\nan escalated set of permissions and actions, pending the user has those roles in the RBAC schema. Because bearer tokens\nare short lived, the user may chose to use the login function instead of directly providing a bearer token. The downside\nto this is that user credentials are directly exposed, and may end up in logs. When using the login function, the Gremlin API will return a bearer token which will be used on the users behalf to\nexecute API actions.\n\n#### Authentication Method Toggles\n\n***Experimental - Improper use can lock you out of your account***\n\n```python\ntoggles_body = {\n    \"companyId\" : hooli_id,\n    \"passwordEnabled\" : True,\n    \"mfaRequired\" : False,\n    \"googleEnabled\" : True,\n    \"oauthEnabled\" : True,\n    \"samlEnabled\" : True,\n    \"claimsRequired\" : False,\n}\n\nGremlinAPIOAUTH.toggles(**toggles_body)\n```\n\n#### API User Keys\n\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nconfig.api_key = 'Key MU3...ZiTk...Lo...4zO..c='\n```\n\n#### User Provided Bearer Token\n\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nconfig.bearer_token = 'Bearer MU3...ZiTk...Lo...4zO..c='\n```\n\n#### User Login\n\n```python\nimport gremlinapi\ngremlinapi.login(\n    email='user@gremlin.com',\n    password='looksL1keIshouldCh4ng3th1sagain!',\n    company_name=\"Gremlin Inc.\"\n)\n```\n\n#### User Login with MFA\n\n```python\nimport gremlinapi\ngremlinapi.login(\n    email='user@gremlin.com',\n    password='looksL1keIshouldCh4ng3th1sagain!',\n    company_name=\"Gremlin Inc.\",\n    token=\"8675309\"\n)\n```\n\n#### Team IDs\n\nWhen using a Gremlin RBAC enabled account, you must specify the `teamId` to parameter for most requests. Additionally,\nyou may supply this globally via the `GremlinAPIConfig` module:\n\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nconfig.team_id = team_id\n```\n\n### OAUTH\n\n#### Authentication with OAUTH\n\nTo authentication through a desired OAUTH workflow, the required information is similar to `gremlinapi.login()`.\n\nWhen successfully authenticated through OAUTH, the bearer token, used later in the API workflow, is returned.\n\n```python\nfrom gremlinapi.oauth import GremlinAPIOAUTH\n\nGREMLIN_COMPANY = \"Your Company Name\"\nUSERNAME = \"your.login.email@domain.com\"\nPASSWORD = \"y0urPa$$w0rd\"\nOAUTH_LOGIN = \"http://your.oauth.provider/login\"\n\nauth_args = {\n    \"email\":USERNAME,\n    \"password\": PASSWORD,\n    \"client_id\": \"mocklab_oauth2\",\n    \"company_name\": GREMLIN_COMPANY,\n    \"oauth_login_uri\": OAUTH_LOGIN,\n}\n\nbearer_token = GremlinAPIOAUTH.authenticate(**auth_args)\n```\n\n#### OAUTH Configuration\n\nOAUTH can be configured through an API endpoint per the following configuration dictionary and code example.\n\nYou must previous be logged in or otherwise authenticated for the below code to succeed.\n\n```python\nfrom gremlinapi.oauth import GremlinAPIOAUTH\n\nGREMLIN_TEAM_ID = \"your-team-id\"\n\nconfig_body = {\n    # Used to authenticate against the OAuth provider. We will redirect the user to this URL when they initate a OAuth login.\n    \"authorizationUri\": \"http://your.oauth.provider/authorize\",\n    # Used to exchange an OAuth code, obtained after logging into the OAuth provider, for an access token.\n    \"tokenUri\": \"http://your.oauth.provider/oauth/token\",\n    # Used to query for the email of the user..\n    \"userInfoUri\": \"http://your.oauth.provider/userinfo\",\n    # The public identifier obtained when registering Gremlin with your OAuth provider.\n    \"clientId\": \"your_client_id\",\n    # The secret obtained when registering Gremlin with your OAuth provider.\n    \"clientSecret\": \"your_client_secret\",\n    # Define what level of access the access token will have that Gremlin obtains during the OAuth login. The default is `email`. If you change it from the default, the scope provided \u003cstrong\u003emust\u003c/strong\u003e be able to read the email of the user.\n    \"scope\":\"email\",\n}\n\nGremlinAPIOAUTH.configure(GREMLIN_TEAM_ID, **config_body)\n```\n\n## Proxy Support\n\nThis library supports system wide `HTTP_PROXY` and `HTTPS_PROXY` environment variables.\n\nAdditionally, proxy configuration may be directly configured inside the library, or the use of \n`GREMLIN_HTTP_PROXY` and `GREMLIN_HTTPS_PROXY` can be utilized to isolate the communication stream.\n\n### Direct Proxy Configuration\n\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nconfig.http_proxy = 'http://user:pass@myproxy:port'\nconfig.https_proxy = 'https://user:pass@myproxy:port'\n```\n\n## Examples\n\nSee [Examples](examples/README.md) for more more functionality\n\n### Launching Attacks\n\n#### Example 1\n\nThis will launch a 100ms latency attack, limited to ICMP traffic, against a single random container\nwith the ECS container-name `swissknife`\n\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nfrom gremlinapi.attacks import GremlinAPIAttacks as attacks\nconfig.bearer_token = 'Bearer MU....ziTk....40z...c='\nconfig.team_id = 'e7352a6b-a9a0-513c-81e4-980f680a70c4'\nbody = {\n    'target': {\n        'type': 'Random',\n        'containers': {\n            'multiSelectLabels': {\n                \"com.amazonaws.ecs.container-name\": [\n                    \"swissknife\"\n                ]\n            }\n        },\n        'exact': 1\n    },\n    'command': {\n        'type': 'latency',\n        'commandType': 'Latency',\n        'args': [\n            '-l', '60',\n            '-h', '^api.gremlin.com',\n            '-m', '100',\n            '-P', 'ICMP'\n        ],\n        'providers': []\n    }\n}\nattack_guid = attacks.create_attack(body=body, teamId=config.team_id)\n```\n\n### Organization and Team management\n\n#### List all teams\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nfrom gremlinapi.orgs import GremlinAPIOrgs as orgs\nconfig.bearer_token = 'Bearer MU3...ZiTk...Lo...4zO..c='\nall_orgs = orgs.list_orgs()\n```\n\n```python\nimport pprint\npprint.pprint(all_orgs)\n```\n\n```javascript\n[\n    {\n        'active': True,\n        'auto_add_users': False,\n        'certificate_expiration_imminent': False,\n        'certificate_expires_on': '2021-02-02T18:38:54.000Z',\n        'certificate_set_at': '2020-02-03T18:38:54.654Z',\n        'certificate_set_by': 'community@gremlin.com',\n        'company_id': '07814fbb-a9a0-81e4-b375-980f680a70c4',\n        'created_at': '2020-02-03T18:38:54.654Z',\n        'identifier': 'cb7ca0d3-4bac-542c-9059-3ee48df857fa',\n        'idle': False,\n        'name': 'testteam1',\n        'secret_set_at': '2020-02-03T18:38:54.654Z',\n        'secret_set_by': 'community@gremlin.com',\n        'updated_at': '2020-02-03T18:38:54.654Z'\n    },\n    {\n        'active': True,\n        'auto_add_users': False,\n        'certificate_expiration_imminent': False,\n        'certificate_expires_on': '2021-02-02T18:40:33.000Z',\n        'certificate_set_at': '2020-02-03T18:40:33.967Z',\n        'certificate_set_by': 'community@gremlin.com',\n        'company_id': '07814fbb-a9a0-81e4-b375-980f680a70c4',\n        'created_at': '2020-02-03T18:40:33.967Z',\n        'identifier': 'c049bf49-f236-5df7-9e2e-5c3858e32426',\n        'idle': False,\n        'name': 'testteam2',\n        'secret_set_at': '2020-02-03T18:40:33.967Z',\n        'secret_set_by': 'community@gremlin.com',\n        'updated_at': '2020-02-03T18:40:33.967Z'\n    },\n    {\n        'active': True,\n        'auto_add_users': False,\n        'certificate_expiration_imminent': False,\n        'certificate_expires_on': '2021-03-19T18:03:54.000Z',\n        'certificate_set_at': '2020-03-19T18:03:54.355Z',\n        'certificate_set_by': 'community@gremlin.com',\n        'company_id': '07814fbb-a9a0-81e4-b375-980f680a70c4',\n        'created_at': '2020-03-19T18:03:54.355Z',\n        'identifier': 'df51deb3-3fa6-5e9e-947f-9d5ef62418f1',\n        'idle': False,\n        'name': 'My New Awesome Team Name',\n        'updated_at': '2020-03-19T18:03:54.355Z'\n    }\n]\n```\n\n#### Create a team\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nfrom gremlinapi.orgs import GremlinAPIOrgs as orgs\nconfig.bearer_token = 'Bearer MU3...ZiTk...Lo...4zO..c='\nnew_team_details = orgs.create_org(name='My New Awesome Team Name')\n```\n\n```python\nimport pprint\npprint.pprint(new_team_details)\n```\n\n```javascript\n{\n    'has_secret': True,\n    'org_id': 'e7352a6b-a9a0-513c-81e4-980f680a70c4',\n    'pem_encoded_certificate': '-----BEGIN CERTIFICATE-----\\nMIIBvDCCA ....=\\n-----END CERTIFICATE-----\\n',\n    'pem_encoded_private_key': '-----BEGIN EC PRIVATE KEY-----\\nMHcCAQEE ....\\n-----END EC PRIVATE KEY-----\\n'\n}\n```\n\n### Scenarios\n\n#### List all scenarios\n\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nfrom gremlinapi.scenarios import GremlinAPIScenarios as scenarios\nconfig.bearer_token = 'Bearer MU3...ZiTk...Lo...4zO..c='\nteam_id = 'e7352a6b-a9a0-513c-81e4-980f680a70c4'\nscenarios_list = scenarios.list_scenarios(teamId=team_id)\n```\n\n```python\nimport pprint\npprint.pprint(scenarios_list)\n```\n\n```javascript\n[\n    {\n        'create_source': 'WebApp',\n        'created_at': '2019-10-14T21:02:47.397Z',\n        'created_by': 'community@gremlin.com',\n        'description': 'Confidently adopt cloud auto-scaling services. Verify your '\n        'users have a positive experience and your application '\n        'behaves as expected while hosts come and go.',\n        'guid': 'ed49ebae-d45d-4412-89eb-aed45d841255',\n        'hypothesis': 'When CPU usage ramps up and hits a set threshold, active '\n        'instances will increase and decrease when CPU usage goes '\n        'down. User sessions will remain active without throwing any '\n        'errors.',\n        'last_run_at': '2019-10-14T21:02:47.865Z',\n        'name': 'Validate Auto-Scaling',\n        'org_id': 'e7352a6b-a9a0-513c-81e4-980f680a70c4',\n        'recommended_scenario_id': 'd543fb53-cbd8-4b92-83fb-53cbd8cb9250',\n        'state': 'PUBLISHED',\n        'steps': [{\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '5',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 5\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            },\n            {\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '10',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 10\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            },\n            {\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '15',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 15\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            },\n            {\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '20',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 20\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            }\n        ],\n        'tiers': ['Free', 'Enterprise'],\n        'updated_at': '2019-10-14T21:02:48.107Z'\n    },\n    {\n        'create_source': 'WebApp',\n        'created_at': '2019-10-14T20:36:59.952Z',\n        'created_by': 'community@gremlin.com',\n        'description': 'Confidently adopt cloud auto-scaling services. Verify your '\n        'users have a positive experience and your application '\n        'behaves as expected while hosts come and go.',\n        'guid': 'bdaeef1c-4dbd-47bd-aeef-1c4dbdf7bd3a',\n        'hypothesis': 'When CPU usage ramps up and hits a set threshold, active '\n        'instances will increase and decrease when CPU usage goes '\n        'down. User sessions will remain active without throwing any '\n        'errors.',\n        'last_run_at': '2019-10-14T20:37:00.128Z',\n        'name': 'Validate Auto-Scaling',\n        'org_id': 'e7352a6b-a9a0-513c-81e4-980f680a70c4',\n        'recommended_scenario_id': 'd543fb53-cbd8-4b92-83fb-53cbd8cb9250',\n        'state': 'PUBLISHED',\n        'steps': [{\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '5',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 5\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            },\n            {\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '10',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 10\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            },\n            {\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '15',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 15\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            },\n            {\n                'attacks': [{\n                    'attackType': 'ILFI',\n                    'impactDefinition': {\n                        'commandArgs': {\n                            'allCores': True,\n                            'cliArgs': ['cpu',\n                                '-l',\n                                '60',\n                                '-p',\n                                '20',\n                                '-a'\n                            ],\n                            'length': 60,\n                            'percent': 20\n                        },\n                        'commandType': 'CPU'\n                    },\n                    'targetDefinition': {\n                        'strategy': {\n                            'percentage': 100\n                        },\n                        'strategyType': 'Random',\n                        'targetType': 'Container'\n                    }\n                }],\n                'delay': 5\n            }\n        ],\n        'tiers': ['Free', 'Enterprise'],\n        'updated_at': '2019-10-14T20:37:00.314Z'\n    },\n    ....\n]\n```\n\n#### Create scenario\n```python\nfrom gremlinapi.config import GremlinAPIConfig as config\nfrom gremlinapi.attack_helpers import (\n    GremlinBlackholeAttack,\n    GremlinTargetContainers,\n)\nfrom gremlinapi.scenarios import GremlinAPIScenarios as scenarios\nfrom gremlinapi.scenario_graph_helpers import (\n    GremlinScenarioGraphHelper,\n    GremlinScenarioILFINode,\n    GremlinScenarioDelayNode\n)\n# config.bearer_token = 'Bearer MU3...ZiTk...Lo...4zO..c='\nconfig.api_key = \"\" #TODO: populate\nconfig.team_id = \"\" #TODO: populate\n# Nodes in a scenario limited to 50. Attempting to add more past this will result in an exception.\n# To override, set this config variable to `True`\nconfig.override_node_count = True\n# Blast Radius in a scenario limited to 1000. Attempting to add more past this will result in an exception.\n# To override, set this config variable to `True`\nconfig.override_blast_radius = True\n\nblast_radius = 100\ndelay_time = 5\n\n#create scenario\nnew_scenario = GremlinScenarioGraphHelper(\n    name=\"A Code-Created Scenario\",\n    description=\"Python SDK created scenario\",\n    hypothesis=\"No Hypothesis\",\n)\n\n#create scenario nodes\nblack_hole_node_1 = GremlinScenarioILFINode(\n    command=GremlinBlackholeAttack(),\n    target=GremlinTargetContainers(\n        strategy_type=\"Random\", labels={\"owner\": \"kyle\"}, percent=blast_radius\n    ),\n)\ndelay_node_1 = GremlinScenarioDelayNode(description=\"Add some delay\", delay=delay_time)\nblack_hole_node_2 = GremlinScenarioILFINode(\n    command=GremlinBlackholeAttack(),\n    target=GremlinTargetContainers(\n        strategy_type=\"Random\", labels={\"owner\": \"kyle\"}, percent=blast_radius\n    ),\n)\n\n#NOTE: The first node added becomes the `HEAD` node \n#add scenario nodes\nnew_scenario.add_node(black_hole_node_1)\nnew_scenario.add_node(black_hole_node_2)\nnew_scenario.add_node(delay_node_1)\n\n#NOTE: All edges stem from the head node. The source node argument of your first add_edge must be the head node.\nnew_scenario.set_head_node(black_hole_node_2)\n#add node edges\nnew_scenario.add_edge(black_hole_node_2, delay_node_1)\nnew_scenario.add_edge(delay_node_1, black_hole_node_1)\n\n#submit scenario to api\nscenarios.create_scenario(body=new_scenario)\n```\n\n## Support\n\nSupport for this library is provided by the Chaos Engineering community.\n[Join us on slack!](https://www.gremlin.com/slack/)\n","funding_links":[],"categories":["Chaos engineering","Datasets, Simulators, and Labs"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgremlin%2Fgremlin-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgremlin%2Fgremlin-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgremlin%2Fgremlin-python/lists"}