consul.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include "consul.h"
  2. #include "http_client.h"
  3. #include "json.hpp"
  4. using json = nlohmann::json;
  5. #define PROTOCOL "http://"
  6. #define API_VERSION "v1"
  7. static const char url_register[] = "/agent/service/register";
  8. static const char url_deregister[] = "/agent/service/deregister";
  9. static const char url_discover[] = "/catalog/service";
  10. static string make_url(const char* ip, int port, const char* url) {
  11. return asprintf(PROTOCOL "%s:%d/" API_VERSION "%s", ip, port, url);
  12. }
  13. static string make_ServiceID(consul_service_t* service) {
  14. return asprintf("%s-%s:%d", service->name, service->ip, service->port);
  15. }
  16. /*
  17. {
  18. "ID": "redis1",
  19. "Name": "redis",
  20. "Tags": [
  21. "primary",
  22. "v1"
  23. ],
  24. "Address": "127.0.0.1",
  25. "Port": 8000,
  26. "Meta": {
  27. "redis_version": "4.0"
  28. },
  29. "EnableTagOverride": false,
  30. "Check": {
  31. "DeregisterCriticalServiceAfter": "90m",
  32. "Args": ["/usr/local/bin/check_redis.py"],
  33. "HTTP": "http://localhost:5000/health",
  34. "Interval": "10s",
  35. "TTL": "15s"
  36. },
  37. "Weights": {
  38. "Passing": 10,
  39. "Warning": 1
  40. }
  41. }
  42. */
  43. int register_service(consul_node_t* node, consul_service_t* service, consul_health_t* health) {
  44. HttpRequest req;
  45. req.method = HTTP_PUT;
  46. req.url = make_url(node->ip, node->port, url_register);
  47. req.content_type = APPLICATION_JSON;
  48. json jservice;
  49. jservice["Name"] = service->name;
  50. if (*service->ip) {
  51. jservice["Address"] = service->ip;
  52. }
  53. jservice["Port"] = service->port;
  54. jservice["ID"] = make_ServiceID(service);
  55. json jcheck;
  56. if (*health->url == '\0') {
  57. snprintf(health->url, sizeof(health->url), "%s:%d", service->ip, service->port);
  58. }
  59. jcheck[health->protocol] = health->url;
  60. jcheck["Interval"] = asprintf("%dms", health->interval);
  61. jcheck["DeregisterCriticalServiceAfter"] = asprintf("%dms", health->interval * 3);
  62. jservice["Check"] = jcheck;
  63. req.body = jservice.dump();
  64. printd("PUT %s\n", req.url.c_str());
  65. printd("%s\n", req.body.c_str());
  66. HttpResponse res;
  67. int ret = http_client_send(&req, &res);
  68. printd("%s\n", res.body.c_str());
  69. return ret;
  70. }
  71. int deregister_service(consul_node_t* node, consul_service_t* service) {
  72. string url = make_url(node->ip, node->port, url_deregister);
  73. url += '/';
  74. url += make_ServiceID(service);
  75. HttpRequest req;
  76. req.method = HTTP_PUT;
  77. req.url = url;
  78. req.content_type = APPLICATION_JSON;
  79. printd("PUT %s\n", req.url.c_str());
  80. HttpResponse res;
  81. int ret = http_client_send(&req, &res);
  82. printd("%s\n", res.body.c_str());
  83. return ret;
  84. }
  85. int discover_services(consul_node_t* node, const char* service_name, std::vector<consul_service_t>& services) {
  86. string url = make_url(node->ip, node->port, url_discover);
  87. url += '/';
  88. url += service_name;
  89. HttpRequest req;
  90. req.method = HTTP_GET;
  91. req.url = url;
  92. HttpResponse res;
  93. printd("GET %s\n", req.url.c_str());
  94. int ret = http_client_send(&req, &res);
  95. if (ret != 0) return ret;
  96. printd("%s\n", res.body.c_str());
  97. json jroot = json::parse(res.body);
  98. if (!jroot.is_array()) return -1;
  99. if (jroot.size() == 0) return 0;
  100. consul_service_t service;
  101. std::string name, ip;
  102. services.clear();
  103. for (size_t i = 0; i < jroot.size(); ++i) {
  104. auto jservice = jroot[i];
  105. name = jservice["ServiceName"];
  106. if (jservice.contains("Address")) {
  107. ip = jservice["Address"];
  108. } else if (jservice.contains("ServiceAddress")) {
  109. ip = jservice["ServiceAddress"];
  110. } else if (jservice.contains("ServiceAddress6")) {
  111. ip = jservice["ServiceAddress6"];
  112. } else {
  113. continue;
  114. }
  115. int port = jservice["ServicePort"];
  116. strncpy(service.name, name.c_str(), sizeof(service.name));
  117. strncpy(service.ip, ip.c_str(), sizeof(service.ip));
  118. service.port = port;
  119. services.emplace_back(service);
  120. }
  121. return 0;
  122. }