consul.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. static const char url_register[] = "/agent/service/register";
  10. static const char url_deregister[] = "/agent/service/deregister";
  11. static const char url_discover[] = "/catalog/service";
  12. static 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. static 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("PUT %s\n", req.url.c_str());
  69. printd("%s\n", req.body.c_str());
  70. HttpResponse res;
  71. int ret = http_client_send(&req, &res);
  72. printd("%s\n", res.body.c_str());
  73. return ret;
  74. }
  75. int deregister_service(consul_node_t* node, consul_service_t* service) {
  76. string url = make_url(node->ip, node->port, url_deregister);
  77. url += '/';
  78. url += make_ServiceID(service);
  79. HttpRequest req;
  80. req.method = HTTP_PUT;
  81. req.url = url;
  82. req.content_type = APPLICATION_JSON;
  83. printd("PUT %s\n", req.url.c_str());
  84. HttpResponse res;
  85. int ret = http_client_send(&req, &res);
  86. printd("%s\n", res.body.c_str());
  87. return ret;
  88. }
  89. int discover_services(consul_node_t* node, const char* service_name, std::vector<consul_service_t>& services) {
  90. string url = make_url(node->ip, node->port, url_discover);
  91. url += '/';
  92. url += service_name;
  93. HttpRequest req;
  94. req.method = HTTP_GET;
  95. req.url = url;
  96. HttpResponse res;
  97. printd("GET %s\n", req.url.c_str());
  98. int ret = http_client_send(&req, &res);
  99. if (ret != 0) {
  100. return ret;
  101. }
  102. printd("%s\n", res.body.c_str());
  103. json jroot = json::parse(res.body.c_str(), NULL, false);
  104. if (!jroot.is_array()) {
  105. return ERR_INVALID_JSON;
  106. }
  107. if (jroot.size() == 0) {
  108. return 0;
  109. }
  110. consul_service_t service;
  111. services.clear();
  112. for (size_t i = 0; i < jroot.size(); ++i) {
  113. auto jservice = jroot[i];
  114. if (!jservice.is_object()) {
  115. continue;
  116. }
  117. auto jname = jservice["ServiceName"];
  118. if (!jname.is_string()) {
  119. continue;
  120. }
  121. auto jip = jservice["ServiceAddress"];
  122. if (!jip.is_string()) {
  123. continue;
  124. }
  125. auto jport = jservice["ServicePort"];
  126. if (!jport.is_number_integer()) {
  127. continue;
  128. }
  129. string name = jname;
  130. string ip = jip;
  131. int port = jport;
  132. strncpy(service.name, name.c_str(), sizeof(service.name));
  133. strncpy(service.ip, ip.c_str(), sizeof(service.ip));
  134. service.port = port;
  135. services.emplace_back(service);
  136. }
  137. return 0;
  138. }