consul.cpp 3.9 KB

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