145 lines
3.9 KiB
C++
145 lines
3.9 KiB
C++
|
#include "consul.h"
|
||
|
|
||
|
#include "HttpClient.h"
|
||
|
using namespace hv;
|
||
|
|
||
|
#include "json.hpp"
|
||
|
using json = nlohmann::json;
|
||
|
|
||
|
#define PROTOCOL "http://"
|
||
|
#define API_VERSION "v1"
|
||
|
|
||
|
static const char url_register[] = "/agent/service/register";
|
||
|
static const char url_deregister[] = "/agent/service/deregister";
|
||
|
static const char url_discover[] = "/catalog/service";
|
||
|
|
||
|
static std::string make_url(const char* ip, int port, const char* url) {
|
||
|
return asprintf(PROTOCOL "%s:%d/" API_VERSION "%s", ip, port, url);
|
||
|
}
|
||
|
|
||
|
static std::string make_ServiceID(consul_service_t* service) {
|
||
|
return asprintf("%s-%s:%d", service->name, service->ip, service->port);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
{
|
||
|
"ID": "redis1",
|
||
|
"Name": "redis",
|
||
|
"Tags": [
|
||
|
"primary",
|
||
|
"v1"
|
||
|
],
|
||
|
"Address": "127.0.0.1",
|
||
|
"Port": 8000,
|
||
|
"Meta": {
|
||
|
"redis_version": "4.0"
|
||
|
},
|
||
|
"EnableTagOverride": false,
|
||
|
"Check": {
|
||
|
"DeregisterCriticalServiceAfter": "90m",
|
||
|
"Args": ["/usr/local/bin/check_redis.py"],
|
||
|
"HTTP": "http://localhost:5000/health",
|
||
|
"Interval": "10s",
|
||
|
"TTL": "15s"
|
||
|
},
|
||
|
"Weights": {
|
||
|
"Passing": 10,
|
||
|
"Warning": 1
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
int register_service(consul_node_t* node, consul_service_t* service, consul_health_t* health) {
|
||
|
HttpRequest req;
|
||
|
req.method = HTTP_PUT;
|
||
|
req.url = make_url(node->ip, node->port, url_register);
|
||
|
req.content_type = APPLICATION_JSON;
|
||
|
|
||
|
json jservice;
|
||
|
jservice["Name"] = service->name;
|
||
|
if (*service->ip) {
|
||
|
jservice["Address"] = service->ip;
|
||
|
}
|
||
|
jservice["Port"] = service->port;
|
||
|
jservice["ID"] = make_ServiceID(service);
|
||
|
|
||
|
json jcheck;
|
||
|
if (*health->url == '\0') {
|
||
|
snprintf(health->url, sizeof(health->url), "%s:%d", service->ip, service->port);
|
||
|
}
|
||
|
jcheck[health->protocol] = health->url;
|
||
|
jcheck["Interval"] = asprintf("%dms", health->interval);
|
||
|
jcheck["DeregisterCriticalServiceAfter"] = asprintf("%dms", health->interval * 3);
|
||
|
jservice["Check"] = jcheck;
|
||
|
|
||
|
req.body = jservice.dump();
|
||
|
printd("PUT %s\n", req.url.c_str());
|
||
|
printd("%s\n", req.body.c_str());
|
||
|
|
||
|
HttpResponse res;
|
||
|
int ret = http_client_send(&req, &res);
|
||
|
printd("%s\n", res.body.c_str());
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int deregister_service(consul_node_t* node, consul_service_t* service) {
|
||
|
std::string url = make_url(node->ip, node->port, url_deregister);
|
||
|
url += '/';
|
||
|
url += make_ServiceID(service);
|
||
|
|
||
|
HttpRequest req;
|
||
|
req.method = HTTP_PUT;
|
||
|
req.url = url;
|
||
|
req.content_type = APPLICATION_JSON;
|
||
|
printd("PUT %s\n", req.url.c_str());
|
||
|
|
||
|
HttpResponse res;
|
||
|
int ret = http_client_send(&req, &res);
|
||
|
printd("%s\n", res.body.c_str());
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int discover_services(consul_node_t* node, const char* service_name, std::vector<consul_service_t>& services) {
|
||
|
std::string url = make_url(node->ip, node->port, url_discover);
|
||
|
url += '/';
|
||
|
url += service_name;
|
||
|
|
||
|
HttpRequest req;
|
||
|
req.method = HTTP_GET;
|
||
|
req.url = url;
|
||
|
|
||
|
HttpResponse res;
|
||
|
printd("GET %s\n", req.url.c_str());
|
||
|
int ret = http_client_send(&req, &res);
|
||
|
if (ret != 0) return ret;
|
||
|
printd("%s\n", res.body.c_str());
|
||
|
|
||
|
json jroot = json::parse(res.body);
|
||
|
if (!jroot.is_array()) return -1;
|
||
|
if (jroot.size() == 0) return 0;
|
||
|
|
||
|
consul_service_t service;
|
||
|
std::string name, ip;
|
||
|
services.clear();
|
||
|
for (size_t i = 0; i < jroot.size(); ++i) {
|
||
|
auto jservice = jroot[i];
|
||
|
name = jservice["ServiceName"];
|
||
|
if (jservice.contains("Address")) {
|
||
|
ip = jservice["Address"];
|
||
|
} else if (jservice.contains("ServiceAddress")) {
|
||
|
ip = jservice["ServiceAddress"];
|
||
|
} else if (jservice.contains("ServiceAddress6")) {
|
||
|
ip = jservice["ServiceAddress6"];
|
||
|
} else {
|
||
|
continue;
|
||
|
}
|
||
|
int port = jservice["ServicePort"];
|
||
|
|
||
|
strncpy(service.name, name.c_str(), sizeof(service.name));
|
||
|
strncpy(service.ip, ip.c_str(), sizeof(service.ip));
|
||
|
service.port = port;
|
||
|
services.emplace_back(service);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|