{"id":23141450,"url":"https://github.com/bessarabov/curry","last_synced_at":"2025-08-17T13:31:51.724Z","repository":{"id":25870775,"uuid":"29310864","full_name":"bessarabov/curry","owner":"bessarabov","description":"Simple system for monitoring. Working in docker.","archived":false,"fork":false,"pushed_at":"2015-02-28T15:08:05.000Z","size":260,"stargazers_count":15,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2023-03-10T21:03:08.749Z","etag":null,"topics":["api","docker","http","monitoring","perl","semver","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Perl6","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bessarabov.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-15T18:12:40.000Z","updated_at":"2022-06-27T05:33:57.000Z","dependencies_parsed_at":"2022-08-24T14:16:07.448Z","dependency_job_id":null,"html_url":"https://github.com/bessarabov/curry","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bessarabov%2Fcurry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bessarabov%2Fcurry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bessarabov%2Fcurry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bessarabov%2Fcurry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bessarabov","download_url":"https://codeload.github.com/bessarabov/curry/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230128411,"owners_count":18177599,"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":["api","docker","http","monitoring","perl","semver","sqlite"],"created_at":"2024-12-17T14:13:44.105Z","updated_at":"2024-12-17T14:13:44.652Z","avatar_url":"https://github.com/bessarabov.png","language":"Perl6","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Project 'curry'\n\n## What is it?\n\nProject curry is a very simple system for monitoring.\n\nIt is a web server that have several endpoints. You can mark the object to be\n'ok' or 'fail' with http requests like:\n\n    curl \".../set?path=my_site\u0026status=ok\"\n    curl \".../set?path=my_other_site\u0026status=fail\"\n\nAnd you can get the current status of your system:\n\n    curl \".../get\"\n\n    {\n        \"status\" : \"fail\",\n        \"objects\" : [\n            {\n                \"path\" : \"my_other_site\",\n                \"status\" : \"fail\"\n            }\n        ]\n    }\n\nProject curry uses [SemVer](http://semver.org/) for version numbers.\n\n## How can I run curry?\n\nFirst you need to [install Docker](https://docs.docker.com/installation/).\n\nThe second (and the last thing) that you need to do is to run the command:\n\n    docker run --publish 15000:3000 bessarabov/curry:1.0.0\n\nIt will download image from [Docker Hub](https://registry.hub.docker.com/u/bessarabov/curry/)\nand it will create working instance on port 15000.\n\nThis way of running is simple and it allows to play with this project. But\nit have on big disadvantage. When you stop the docker instance all the data\nis lost. Please read the next section if you need to have persistent storage.\n\n## How can I run curry with persistent storage?\n\nDocker container with curry has sqlite file. All the data that is stored in\ncurry is stored in that database file. When you delete container that file\nis deleted (as it is situated in the container). To make the storage\npersistent you need to place that file outsite the docker.\n\nFirst of all you need to [Docker to be installed](https://docs.docker.com/installation/).\n\nThen you should pull the image:\n\n    docker pull bessarabov/curry:1.0.0\n\nWhen you have a curry image you can use this commands to copy sqlite file\nfrom the container to your local computer:\n\n    docker run --detach --name tmp_curry bessarabov/curry:1.0.0\n    docker cp tmp_curry:/curry/data/db.sqlite .\n    docker rm -f tmp_curry\n\nNext you should place db.sqlite to some handy path and run curry mounting\nthat path to the container. For example if you have placed db.sqlite to\n/docker/curry you need to run:\n\n    docker run --volume /docker/curry/:/curry/data/ --publish 15000:3000 bessarabov/curry:1.0.0\n\nThis will start curry at port 15000 and it will use database file from your\nhost computer.\n\n## How can I run curry with authorization?\n\nBy default curry has no authorization. Eveybody who has full access to the\ncurry.\n\nSometimes you need to limit the access. To do it you should pass environment\nvariable TOKEN when running docker. Here is an example:\n\n    docker run --publish 15000:3000 -e 'TOKEN=3qagL6jllc' bessarabov/curry:1.0.0\n\nOne will not be able to access curry the standard way:\n\n    curl -H \"X-Requested-With: XMLHttpRequest\" \"http://curry:15000/api/1/get\"\n\nIt will return error:\n\n    {\"error_message\":\"No access\",\"success\":false}\n\nTo access curry you need to specify that token:\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        -H 'Authorization: TOKEN key=\"3qagL6jllc\"' \\\n        \"http://curry:15000/api/1/get\"\n\nAnd be sure to run curry with persistent storage.\n\n## Statuses\n\nObject in curry has a status. It can be 'ok', 'fail' or 'unknown'. Statuses\n'ok' and 'fail' are set manually with API endpoint 'set'. Status 'unknown' is\nset to the object automatically when the date of the last 'ok'/'fail' differ\nfrom the current date for the value of 'expire'.\n\n## API\n\nCurry is a webserver. There are several endpoints that you can access. Here\nis an example:\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/version\"\n\nHere is the answer (the JSON was prettified):\n\n    {\n        \"success\" : true,\n        \"result\" : {\n            \"version\" : \"1.0.0\"\n        }\n    }\n\nAll API endpoints alwasys return unpretty JSON. All the answers have the same\nstructure:\n\n    {\n        \"success\" : true,\n        \"result\" : ...\n    }\n\nThe value \"result\" can be any valid JSON value: string, number, object,\narray, true, false, null. The value of \"result\" differ for different\nendpoints. And \"result\" is optional.\n\nHere is the sample JSON in case of error:\n\n    {\n        \"success\" : false,\n        \"error_message\" : \"Incorrect value for 'path': 'sample path'\"\n    }\n\nThe \"error_message\" is human readable description of the error.\n\nSo, all API endpoints must return JSON. If the endpoint returns not valid\nJSON, this means error. The JSON is always an object that hase name\n\"success\". If \"success\" is a true value then the API request finished\nsuccessfully. If the value of \"success\" is false, this means error and the\ndescription of the error will be in \"error_message\".\n\nThe API is versioned with [SemVer](http://semver.org/). The number in the url\nis the Major version of the curry version. Number of API bumps up when the\nincompatible API change is made.\n\n## List of API endpoints\n\n### set\n\nWith the endpoint \"set\" you record information about state of the object. You\nmust specify 2 parameters:\n\n * path\n * status\n\nParameter \"path\" consists of one or more element. Each element is a string\nthat should match regular exspression [a-z0-9_]+ Elements are separated with\ndots. Some examples of valid paths: \"aa\", \"site\", \"jenkins.job_1\"\n\nParameter \"status\" can be \"ok\" or \"fail\".\n\nWhen you execute this endpoint with new \"path\" you must also specify\nparamenter \"expire\". Parameter expire must match regular exspression\n[0-9]+[smhd] The meaning of \"expire\" is in how much time from the last \"ok\"\nor \"fail\" the object status will be changed to \"unknown\". The meaning of\npostfixes:\n\n * s — second\n * m — minute\n * h — hour\n * d — day\n\nSample usage:\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/set?path=aa\u0026status=ok\u0026expire=1d\"\n\nIt will return:\n\n    {\n        \"success\" : true\n    }\n\n### get\n\nEndpoint \"get\" gives you information of all failed object.\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/get\"\n\nIt will return:\n\n    {\n        \"success\" : true,\n        \"result\" : {\n            \"status\" : \"fail\",\n            \"objects\" : [\n                {\n                    \"path\" : \"bb\",\n                    \"status\" : \"fail\"\n                },\n                {\n                    \"path\" : \"jenkins.job_1\",\n                    \"status\" : \"fail\"\n                }\n            ]\n        }\n    }\n\nYou can limit the data that \"get\" returns with the optional parameter \"path\":\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/get?path=jenkins\"\n\nIn this example I userd \"jenkins\" as the value for \"path\". Such usage will\nreturn all failing objects that has the path starting with \"jenkins.\" and the\n\"jenkins\" object.\n\n    {\n        \"success\" : true,\n        \"result\" : {\n            \"status\" : \"fail\",\n            \"objects\" : [\n                {\n                    \"path\" : \"jenkins.job_1\",\n                    \"status\" : \"fail\"\n                }\n            ]\n        }\n    }\n\n### get_all\n\nThe endpoint \"get_all\" works exactly as \"get\", but it returns all the object.\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/get_all\"\n\nHere is the example output of this endpoint:\n\n    {\n        \"success\" : true,\n        \"result\" : {\n            \"status\" : \"fail\",\n            \"objects\" : [\n                {\n                    \"path\" : \"aa\",\n                    \"status\" : \"ok\"\n                },\n                {\n                    \"status\" : \"fail\",\n                    \"path\" : \"bb\"\n                },\n                {\n                    \"path\" : \"jenkins.job_1\",\n                    \"status\" : \"fail\"\n                },\n                {\n                    \"status\" : \"ok\",\n                    \"path\" : \"jenkins.job_2\"\n                }\n            ]\n        }\n    }\n\nEndpoint \"get_all\" can get optional parameter \"path\". It works exactly as\nin \"get\" endpoint.\n\n### get_object\n\nEndpoint \"get_object\" returns all avaliable information about one object.\nYou must specify parameter \"path\":\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/get_object?path=aa\"\n\nIt will return:\n\n    {\n        \"success\" : true,\n        \"result\" : {\n            \"path\" : \"aa\",\n            \"status\" : \"ok\",\n            \"expire\" : \"1d\",\n            \"history\" : [\n                {\n                    \"status\" : \"ok\",\n                    \"dt\" : \"2015-01-22 06:33:57\"\n                },\n                {\n                    \"status\" : \"ok\",\n                    \"dt\" : \"2015-01-22 06:40:14\"\n                }\n            ]\n        }\n    }\n\n### version\n\nEndpoint \"version\" return the version of the curry system.\n\n    curl \\\n        -H \"X-Requested-With: XMLHttpRequest\" \\\n        \"http://curry:15000/api/1/version\"\n\nIt will return:\n\n    {\n        \"success\" : true,\n        \"result\" : {\n            \"version\" : \"1.0.0\"\n        }\n    }\n\n## FAQ\n\n### Why I need to specify X-Requested-With header?\n\nThis is a security issue. This heades has beed added to prevent\n[CSRF attacks](http://en.wikipedia.org/wiki/Cross-site_request_forgery).\n\nIf there was no such header the attacker could add such code on his site:\n\n    \u003cimg src=\"http://curry:15000/api/1/set?path=aa\u0026status=ok\"/\u003e\n\nAnd if you go to that site that it will change she status of the object. To\nprevent such situation the header was made obligatory.\n\n### How can I run curry with https?\n\nThis is simple. You run curry with docker on some port on localhost and have\nnginx (or other web server) that serves https sitet, but passes all requests\nto that localhost port.\n\n### What is the future of this project?\n\nFor now this project works super well for my purposes. I was thinking about\nseveral things that is good to add to this project, but I don't need that\nfeatures heavily. If you need one of this feature or you have any other\nfeature requests, please write and comment and [GitHub Issues of this\nproject](https://github.com/bessarabov/curry/issues). Writing at GitHub\nwill speed up the addition of the features.\n\nHere is the list of features that I think is good to add to this project:\n\n * endpoint \"delete\" to delete obsolete objects\n * the ability to specify \"never\" as \"expire\" in \"set\" endpoints\n * the ability to use MySQL as the database\n * the ability to specify how many elements will be stored in history (to\n   prevent database of getting very big)\n * hooks — curry could make some http request when the status of the object\n   changes\n * make it possible to specify some key-value for every execution of \"set\"\n   endpoint (this can be used to specify some descriptions, for example one\n   could set \"html\" key that has the value of text describing the error in\n   detail).\n\nAnd there are several things that should be changed in this project:\n\n * Make API more RESTfull — now every endpoint works with GET and POST. We\n   should make 'set' work only with POST and all the endpoints that return\n   data to work with GET. This is backwards-incompatible change, so the major\n   version in SemVer should be bumped.\n * Now every endpoint has must get 'X-Requested-With' header. But actually\n   it is needed only for endpoints that changes data (now there is only one\n   endpoint 'set'). So we should remove the need of this header for all\n   endpoints that just return data ('get', 'get_all', 'get_object',\n   'version'). This is backwards-incompatible change, so the major version in\n   SemVer should be bumped.\n * Review all the http statuses the endpionts return (especially the\n   situations with errors) and change in case something is not consistent\n * Check the situation when you use 'set' endpoint and change only 'expire'\n   paramter of the object. Make sure that it works as expected when this\n   changes the status of the object to 'unknown'\n * Make sure that the system works in the situation when somebody specifies\n   very big value for expire (for example '10000000000000d')\n\n### How can I build docker image myself?\n\nThe docker images is build automatically at [Docker Hub](https://registry.hub.docker.com/u/bessarabov/curry/)\nbut it is pretty easy to build the image yourself:\n\n    git clone https://github.com/bessarabov/curry.git\n    cd curry\n    docker build --tag curry .\n\n### How to make new release?\n\nThis is information for developers of this project. It is a checklist to be\ndone when releasing new version.\n\n * Make the changes to the code\n * Run tests `time docker build --tag curry .; prove t_docker/`\n * Find out what SemVer version should be used for new release\n * Change the docs to use new SemVer version number\n * Add list of changes to the Changes file\n * Add git tag\n * Push to GitHub\n * Add new tag to the automated build at Docker Hub\n\n## Publications\n\n * http://blogs.perl.org/users/ivan_bessarabov/2015/02/using-perl-dancer-and-docker-to-create-simple-monitoring-system.html\n * https://ivan.bessarabov.ru/blog/curry-monitoring (in Russian language)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbessarabov%2Fcurry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbessarabov%2Fcurry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbessarabov%2Fcurry/lists"}