CtlUtil.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* (c) ZeroTier, Inc.
  2. * See LICENSE.txt in nonfree/
  3. */
  4. #include "CtlUtil.hpp"
  5. #ifdef ZT_CONTROLLER_USE_LIBPQ
  6. #include <iomanip>
  7. #include <sstream>
  8. #ifdef ZT1_CENTRAL_CONTROLLER
  9. #include <google/cloud/bigtable/admin/bigtable_table_admin_client.h>
  10. #include <google/cloud/bigtable/admin/bigtable_table_admin_connection.h>
  11. #include <google/cloud/bigtable/table.h>
  12. #include <google/cloud/pubsub/admin/subscription_admin_client.h>
  13. #include <google/cloud/pubsub/admin/subscription_admin_connection.h>
  14. #include <google/cloud/pubsub/admin/topic_admin_client.h>
  15. #include <google/cloud/pubsub/message.h>
  16. #include <google/cloud/pubsub/subscriber.h>
  17. #include <google/cloud/pubsub/subscription.h>
  18. #include <google/cloud/pubsub/topic.h>
  19. namespace pubsub = ::google::cloud::pubsub;
  20. namespace pubsub_admin = ::google::cloud::pubsub_admin;
  21. namespace bigtable_admin = ::google::cloud::bigtable_admin;
  22. #endif
  23. namespace ZeroTier {
  24. const char* _timestr()
  25. {
  26. time_t t = time(0);
  27. char* ts = ctime(&t);
  28. char* p = ts;
  29. if (! p)
  30. return "";
  31. while (*p) {
  32. if (*p == '\n') {
  33. *p = (char)0;
  34. break;
  35. }
  36. ++p;
  37. }
  38. return ts;
  39. }
  40. std::vector<std::string> split(std::string str, char delim)
  41. {
  42. std::istringstream iss(str);
  43. std::vector<std::string> tokens;
  44. std::string item;
  45. while (std::getline(iss, item, delim)) {
  46. tokens.push_back(item);
  47. }
  48. return tokens;
  49. }
  50. std::string url_encode(const std::string& value)
  51. {
  52. std::ostringstream escaped;
  53. escaped.fill('0');
  54. escaped << std::hex;
  55. for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
  56. std::string::value_type c = (*i);
  57. // Keep alphanumeric and other accepted characters intact
  58. if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
  59. escaped << c;
  60. continue;
  61. }
  62. // Any other characters are percent-encoded
  63. escaped << std::uppercase;
  64. escaped << '%' << std::setw(2) << int((unsigned char)c);
  65. escaped << std::nouppercase;
  66. }
  67. return escaped.str();
  68. }
  69. std::string random_hex_string(std::size_t length)
  70. {
  71. static const char hex_chars[] = "0123456789abcdef";
  72. std::random_device rd;
  73. std::mt19937 gen(rd());
  74. std::uniform_int_distribution<> dis(0, 15);
  75. std::string result;
  76. result.reserve(length);
  77. for (std::size_t i = 0; i < length; ++i) {
  78. result += hex_chars[dis(gen)];
  79. }
  80. return result;
  81. }
  82. #ifdef ZT1_CENTRAL_CONTROLLER
  83. void create_gcp_pubsub_topic_if_needed(std::string project_id, std::string topic_id)
  84. {
  85. // This is a no-op if the topic already exists.
  86. auto topicAdminClient = pubsub_admin::TopicAdminClient(pubsub_admin::MakeTopicAdminConnection());
  87. auto topicName = pubsub::Topic(project_id, topic_id).FullName();
  88. auto topicResult = topicAdminClient.GetTopic(topicName);
  89. if (! topicResult.ok()) {
  90. // Only create if not found
  91. if (topicResult.status().code() == google::cloud::StatusCode::kNotFound) {
  92. auto createResult = topicAdminClient.CreateTopic(topicName);
  93. if (! createResult.ok()) {
  94. fprintf(stderr, "Failed to create topic: %s\n", createResult.status().message().c_str());
  95. throw std::runtime_error("Failed to create topic");
  96. }
  97. fprintf(stderr, "Created topic: %s\n", topicName.c_str());
  98. }
  99. else {
  100. fprintf(stderr, "Failed to get topic: %s\n", topicResult.status().message().c_str());
  101. throw std::runtime_error("Failed to get topic");
  102. }
  103. }
  104. }
  105. void create_gcp_pubsub_subscription_if_needed(
  106. std::string project_id,
  107. std::string subscription_id,
  108. std::string topic_id,
  109. std::string controller_id)
  110. {
  111. // This is a no-op if the subscription already exists.
  112. auto subscriptionAdminClient =
  113. pubsub_admin::SubscriptionAdminClient(pubsub_admin::MakeSubscriptionAdminConnection());
  114. auto topicName = pubsub::Topic(project_id, topic_id).FullName();
  115. auto subscriptionName = pubsub::Subscription(project_id, subscription_id).FullName();
  116. auto sub = subscriptionAdminClient.GetSubscription(subscriptionName);
  117. if (! sub.ok()) {
  118. if (sub.status().code() == google::cloud::StatusCode::kNotFound) {
  119. fprintf(stderr, "Creating subscription %s for topic %s\n", subscriptionName.c_str(), topicName.c_str());
  120. google::pubsub::v1::Subscription request;
  121. request.set_name(subscriptionName);
  122. request.set_topic(pubsub::Topic(project_id, topic_id).FullName());
  123. request.set_filter("(attributes.controller_id=\"" + controller_id + "\")");
  124. auto createResult = subscriptionAdminClient.CreateSubscription(request);
  125. if (! createResult.ok()) {
  126. fprintf(stderr, "Failed to create subscription: %s\n", createResult.status().message().c_str());
  127. throw std::runtime_error("Failed to create subscription");
  128. }
  129. fprintf(stderr, "Created subscription: %s\n", subscriptionName.c_str());
  130. }
  131. else {
  132. fprintf(stderr, "Failed to get subscription: %s\n", sub.status().message().c_str());
  133. throw std::runtime_error("Failed to get subscription");
  134. }
  135. }
  136. }
  137. // void create_bigtable_table(std::string project_id, std::string instance_id)
  138. // {
  139. // auto bigtableAdminClient =
  140. // bigtable_admin::BigtableTableAdminClient(bigtable_admin::MakeBigtableTableAdminConnection());
  141. // std::string table_id = "member_status";
  142. // std::string table_name = "projects/" + project_id + "/instances/" + instance_id + "/tables/" + table_id;
  143. // // Check if the table exists
  144. // auto table = bigtableAdminClient.GetTable(table_name);
  145. // if (! table.ok()) {
  146. // if (table.status().code() == google::cloud::StatusCode::kNotFound) {
  147. // google::bigtable::admin::v2::Table table_config;
  148. // table_config.set_name(table_id);
  149. // auto families = table_config.mutable_column_families();
  150. // // Define column families
  151. // // Column family "node_info" with max 1 version
  152. // // google::bigtable::admin::v2::ColumnFamily* node_info = table_config.add_column_families();
  153. // // Column family "check_in" with max 1 version
  154. // auto create_result = bigtableAdminClient.CreateTable(
  155. // "projects/" + project_id + "/instances/" + instance_id, table_id, table_config);
  156. // if (! create_result.ok()) {
  157. // fprintf(
  158. // stderr, "Failed to create Bigtable table member_status: %s\n",
  159. // create_result.status().message().c_str());
  160. // throw std::runtime_error("Failed to create Bigtable table");
  161. // }
  162. // fprintf(stderr, "Created Bigtable table: member_status\n");
  163. // }
  164. // else {
  165. // fprintf(stderr, "Failed to get Bigtable table member_status: %s\n", table.status().message().c_str());
  166. // throw std::runtime_error("Failed to get Bigtable table");
  167. // }
  168. // }
  169. // }
  170. #endif
  171. } // namespace ZeroTier
  172. #endif