consul.cpp 3.9 KB

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