{"id":21888638,"url":"https://github.com/swisscom/dopc","last_synced_at":"2025-07-21T10:31:16.773Z","repository":{"id":18691760,"uuid":"85068064","full_name":"swisscom/dopc","owner":"swisscom","description":"Deployment Orchestrator for Puppet - Controller","archived":false,"fork":false,"pushed_at":"2023-04-07T12:00:27.000Z","size":128,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":22,"default_branch":"master","last_synced_at":"2023-10-25T17:08:41.053Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","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/swisscom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-03-15T12:10:04.000Z","updated_at":"2022-02-14T05:44:29.000Z","dependencies_parsed_at":"2022-07-26T23:32:02.313Z","dependency_job_id":"a6511fcc-c0f3-4685-bc0d-6bca943a292b","html_url":"https://github.com/swisscom/dopc","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fdopc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fdopc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fdopc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swisscom%2Fdopc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swisscom","download_url":"https://codeload.github.com/swisscom/dopc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226902943,"owners_count":17700619,"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-11-28T11:16:22.766Z","updated_at":"2024-11-28T11:16:23.288Z","avatar_url":"https://github.com/swisscom.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e [!NOTE]\n\u003e DEPRECATED - no longer maintained!\n\n# DOPc\n\nDOPc combines DOPi and DOPv in one tools and exposes a REST API.\n\n## Requirements\n\nSee `Gemfile` for required gems.\n\n## Quickstart\n\n1. Set up Ruby environmnent: RVM, Bundler, etc.\n1. Create configuration `config/dopc.yml` (see `config/dopc.yml.example` for an\n   example) and set the authentication token in the config (use e.g. `openssl\n   rand -base64 32` for random token)\n1. Setup database: `bundle exec rake db:migrate`\n1. Start server: `bundle exec rails s`\n1. Start Delayed::Job to start processing plan executions: `bundle exec bin/delayed_job start`\n\n## Configuration\n\nDOPc will use configuration settings from DOPi/DOPv wherever possible. When\ninvoking DOPi it will load the configuration file from DOPi first. All DOPc\nspecific configuration goes to `config/dopc.yml`.\n\n## Authentication\n\nAll requests must must be authenticated by using an authorization token in the\nHTTP header of the form `Authorization: Token token=[\"]\u003ctoken\u003e[\"]`.\n\n## Maintenance\n\nIf for any reason executions are not scheduled to run you can do so manually by\nrunning `bundle exec rake dopc:schedule`. This can for example happen if\nDelayed::Job is restarted with pending executions.\n\nLogs are not rotated automatically. To truncate logs use `bundle exec rake\nlog:clear:all`. In error cases it can happen that executions log files are left\nover, then use `bundle exec rake log:clear:exe` to delete them.\n\n## Implementation\n\n* Plans are executed in background with Delayed::Job.\n* Scheduling plan executions is done everytime a new execution is added or an\n  execution finishes.\n* When restarting scheduling must be done manually with the `dopc:schedule`\n  rake task.\n* Plans are managed with the plan store from dop_common, nothing is stored in\n  the local database. Plans and executions are connected only by the plan name\n  (no IDs).\n* Only one execution for a specific plan can be running or queued at a time.\n* Before calling DOPi its configuration is loaded from file (usually\n  `~/.dop/dopi.conf`, except when the Rails environment is `test`, then also\n  all executions are started with the `noop` option.\n* Be careful with mocking and setup/teardown in tests, may cause trouble with\n  unclean state in tests or leaving over tmp files/logs/etc.\n\n## Troubleshooting\n\nRails logs everything to `log/\u003cenvironment\u003e.log`. Delayed::Job runs in separate\nprocesses and logs to `log/jobs_\u003cenvironment\u003e.log`. Executions log to\nindividual log files in `log/executions_\u003cenvironment\u003e/\u003cjob_id\u003e.log`.\n\n## Contributing\n\n* Be sure that API specifiction in this file is consistent with the code.\n\n## Releasing\n\nTODO\n\n## Caveats\n\n* When crashing pending executions will not necessarily be scheduled after\n  restart. Only if there is at least one queued execution or some execution is\n  added added/deleted.\n* Logging per execution works only as long as a job is executed in its own Ruby\n  process (which is the case with Delayed::Job) since the log is set globally.\n  In future this may require to set individual log objects for each DOPv/DOPi\n  run.\n* Encoding of run_for_nodes parameter as YAML dump of an OpenStruct is ugly.\n  Expand parameters and document?\n\n## Todo\n\n* Test recovering failed workers\n* Some things are not tested: e.g. Invalid/missing parameters or invalid\n  combinations of parameters, certain scenarios like remove plan during run.\n  Could use more tests. Also think about splitting up test files not by\n  controller but by scenarios. Some integration tests concern more than one\n  controller. Some things are not easy to test.\n\n## API Specification\n\n### General Errors\n\n**406 Not acceptable**\n\nReturned if the client does set an `Accept` HTTP header that does not accept\n`application/json` format. All answers are in JSON format and the client must\naccept it.\n\n**415 Unsupported media type**\n\nReturned if the `Content-Type` HTTP header is set and does not equal\n`application/json`. All payload data sent must be in JSON format and the\ncontent type header must indicate so if not empty.\n\n**401 Unauthorized**\n\nReturned if the client does not use HTTP authorization or the authorization\ntoken is wrong.\n\n**5xx Server Error**\n\nReturned if something unexpected goes wrong on the server side.\n\n### Version 1\n\n* Client must accept `application/json` (`Accept` header)\n* Submitted payload must be `application/json` (`Content-Type` header)\n* Client must authenticate with token (`Authorization` header)\n\n#### GET /v1/ping\n\nPing the service.\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | pong | Contains value `pong` | yes |\n\n#### GET /v1/plans\n\nGet list of all plans.\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| Array | plans | List of all plans | yes |\n| String | \u0026nbsp;\u0026nbsp;- name | Name of the plan | no |\n\n#### GET /v1/plans/{name}\n\nGet content of a plan.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**Request Body**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | version | Version string, if not specified then 'latest' is assumed. | no |\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | content | Base64 encoded string with YAML content of the plan | yes |\n\n**404 Not Found**\n\nIf the specified plan or version was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### GET /v1/plans/{name}/versions\n\nGet a list of all versions of a plan.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| Array | versions | List of all versions | yes |\n| String | \u0026nbsp;\u0026nbsp;- name | Name of the version | no |\n\n**404 Not Found**\n\nIf the specified plan was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### POST /v1/plans\n\nAdd a new plan. The plan name is taken from the content.\n\n**Request Body**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | content | Base64 encoded string with YAML content of the plan | yes |\n\n**201 Created**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**422 Unprocessable Entity**\n\nIf the content can not be loaded.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n**400 Bad Request**\n\nIf the plan can not be added, e.g. it already exists or is invalid.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### PUT /v1/plans\n\nUpdate an existing plan. Either create a new version, then a plan file must be\nspecified. Or just update the state of an existing plan, then the plan name\nmust be specified.\n\n**Request Body**\n\nEither plan or content is required.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | content | Base64 encoded string with YAML content of the plan | no |\n| String | plan | Plan name | no |\n| Boolean | clear | Remove current DOPi state and start with clean state (if empty defaults to false) | no |\n| Boolean | ignore | Ignore update and just set new version (if empty defaults to false) | no |\n\n**200 Success**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**422 Unprocessable Entity**\n\nIf the content can not be loaded.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n**400 Bad Request**\n\nIf the plan can not be added, e.g. it does not yet exist.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### DELETE /v1/plans/{name}\n\nDelete a plan with all its versions.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of plan that was deleted | yes |\n\n**404 Not Found**\n\nIf the specified plan was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### PUT /v1/plans/{name}/reset\n\nReset the state of a plan.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**Request Body**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| Boolean | force | Force the state reset, default is false | no |\n\n**200 Success**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan that was reset | yes |\n\n**422 Unprocessable Entity**\n\nIf the request is invalid.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n**404 Not Found**\n\nIf the plan was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### GET /v1/plans/{name}/state\n\nGet current DOPi state of a plan.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| String | name | Name of the plan | yes |\n\n**200 Success**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | state | State of the plan, newline formatted | yes |\n\n**404 Not Found**\n\nIf the plan was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### GET /v1/executions\n\nGet list of all executions.\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| Array | executions: | List of all executions | yes |\n| Integer | \u0026nbsp;\u0026nbsp;- id | ID of the execution | yes |\n| String | \u0026nbsp;\u0026nbsp;- plan | Plan to execute | yes |\n| String | \u0026nbsp;\u0026nbsp;- task | Task to execute | yes |\n| String | \u0026nbsp;\u0026nbsp;- stepset | Stepset to execute instead of default | no |\n| Boolean | \u0026nbsp;\u0026nbsp;- rmdisk | Whether to delete disks when undeploying | no |\n| String | \u0026nbsp;\u0026nbsp;- run_for_nodes | Node filters for DOPi encoded as YAML dump of an OpenStruct object| no |\n| String | \u0026nbsp;\u0026nbsp;- status | Execution status | yes |\n| String | \u0026nbsp;\u0026nbsp;- created_at | Timestamp when the execution was created | yes |\n| String | \u0026nbsp;\u0026nbsp;- updated_at | Timestamp when the execution was last updated | yes |\n| String | \u0026nbsp;\u0026nbsp;- started_at | Timestamp when the execution was started | no |\n| String | \u0026nbsp;\u0026nbsp;- finished_at | Timestamp when the execution was finished | no |\n\n#### GET /v1/executions/{id}\n\nGet execution with the specified ID.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| Integer | id | ID of an execution | yes |\n\n**200 OK**\n\nSee the GET on `/executions` for the list of returned properties.\n\n**404 Not Found**\n\nIf the specified execution was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### GET /v1/executions/{id}/log\n\nGet the log of an execution.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| Integer | id | ID of an execution | yes |\n\n**200 OK**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | log | Log of the execution | yes |\n\n**404 Not Found**\n\nIf the specified execution was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### DELETE /v1/executions/{id}\n\nRemove an execution.\n\n**Path Parameters**\n\n| Type | Parameter | Description | Required |\n| --- | --- | --- | --- |\n| Integer | id | ID of an execution | yes |\n\n**200 OK**\n\nSee GET for the list of returned properties.\n\n**404 Not Found**\n\nIf the specified execution was not found.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n**409 Conflict**\n\nIf the specified execution is running and can not be removed.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### POST /v1/executions\n\nExecute a plan. Creates a job to execute the plan in the background.\n\n**Request Body**\n\nFor tasks deploy/undeploy only DOPv is run. For task run only DOPi is run.\nSpecial tasks are:\n\n* setup means deploy followed by run\n* teardown means undeploy followed by resetting DOPi state\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | plan | The name of the plan to execute | yes |\n| String | task | Task to execute, must be one of: deploy, undeploy, run, setup, teardown. | yes |\n| String | stepset | Stepset to run instead of the default, for DOPi | no, can only use with tasks run/setup (if empty the default stepset is used) |\n| Boolean | rmdisk | Whether to delete disks when undeploying, for DOPv | no, can only use with task undeploy (defaults is false) |\n| String | run_for_nodes | Node filters for DOPi, encoded as YAML dump of an OpenStruct object, refer to DOPi or DOPc client documentation for format | no, can only use with tasks run/setup |\n\n**201 Created**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| Integer | id | ID of the created execution | yes |\n\n**422 Unprocessable Entity**\n\nIf request body has errors.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n#### DELETE /v1/executions\n\nRemove executions.\n\n**Request Body**\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| Array of strings | statuses | Remove only executions whose status matches the list| yes |\n| String | plan | Remove only executions that match the plan name | no |\n| Integer | age | Remove only executions that were created at least age seconds ago | no |\n\n**200 OK**\n\nReturns the removed executions. See GET operation for individual executions for the response body format.\n\n**422 Unprocessable Entity**\n\nIf any of the specified statuses is invalid.\n\n| Type | Property | Description | Required |\n| --- | --- | --- | --- |\n| String | error | Error message | yes |\n\n## Authors\n\n* Anselm Strauss \u003cAnselm.Strauss@swisscom.com\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswisscom%2Fdopc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswisscom%2Fdopc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswisscom%2Fdopc/lists"}