1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2014-2017 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #include <lcbio/lcbio.h>
19 #include <lcbio/timer-ng.h>
20 #include <lcbio/timer-cxx.h>
21 #include <libcouchbase/vbucket.h>
22 #include "clconfig.h"
23 
24 #define LOGARGS(mcr, lvlbase) mcr->parent->settings, "bc_static", LCB_LOG_##lvlbase, __FILE__, __LINE__
25 #define LOGFMT "(STATIC=%p)> "
26 #define LOGID(mcr) (void *)mcr
27 
28 using namespace lcb::clconfig;
29 using lcb::Hostlist;
30 
31 
32 // Base class for providers which only generate a config once, statically.
33 class StaticProvider : public Provider {
34 public:
StaticProvider(Confmon * parent_,Method m)35     StaticProvider(Confmon *parent_, Method m)
36         : Provider(parent_, m), async(parent_->iot, this), config(NULL) {
37     }
38 
~StaticProvider()39     virtual ~StaticProvider() {
40         if (config) {
41             config->decref();
42         }
43         async.release();
44     }
45 
get_cached()46     ConfigInfo *get_cached() {
47         return config;
48     }
49 
refresh()50     lcb_error_t refresh() {
51         async.signal();
52         return LCB_SUCCESS;
53     }
54 
configure_nodes(const Hostlist & hl)55     void configure_nodes(const Hostlist& hl) {
56         if (hl.empty()) {
57             lcb_log(LOGARGS(this, FATAL), "No nodes provided");
58             return;
59         }
60 
61         lcbvb_CONFIG *vbc = gen_config(hl);
62         if (vbc != NULL) {
63             if (config != NULL) {
64                 config->decref();
65                 config = NULL;
66             }
67             config = ConfigInfo::create(vbc, type);
68         }
69     }
70 
71     virtual lcbvb_CONFIG* gen_config(const Hostlist& hl) = 0;
72 
73 private:
async_update()74     void async_update() {
75         if (config != NULL) {
76             parent->provider_got_config(this, config);
77         }
78     }
79 
80     lcb::io::Timer<StaticProvider, &StaticProvider::async_update> async;
81     ConfigInfo *config;
82 };
83 
84 
85 /* Raw memcached provider */
86 
87 struct McRawProvider : public StaticProvider {
McRawProviderMcRawProvider88     McRawProvider(Confmon* parent_) : StaticProvider(parent_, CLCONFIG_MCRAW) {
89     }
90     lcbvb_CONFIG *gen_config(const lcb::Hostlist& l);
91 };
92 
gen_config(const lcb::Hostlist & hl)93 lcbvb_CONFIG * McRawProvider::gen_config(const lcb::Hostlist& hl)
94 {
95     std::vector<lcbvb_SERVER> servers;
96     servers.reserve(hl.size());
97 
98     for (size_t ii = 0; ii < hl.size(); ii++) {
99         const lcb_host_t& curhost = hl[ii];
100         servers.resize(servers.size() + 1);
101 
102         lcbvb_SERVER& srv = servers.back();
103         memset(&srv, 0, sizeof srv);
104 
105         /* just set the memcached port and hostname */
106         srv.hostname = (char *)curhost.host;
107         srv.svc.data = std::atoi(curhost.port);
108         if (parent->settings->sslopts) {
109             srv.svc_ssl.data = srv.svc.data;
110         }
111     }
112 
113     lcbvb_CONFIG *newconfig = lcbvb_create();
114     lcbvb_genconfig_ex(newconfig, "NOBUCKET", "deadbeef", &servers[0], servers.size(), 0, 2);
115     lcbvb_make_ketama(newconfig);
116     newconfig->revid = -1;
117     return newconfig;
118 }
119 
new_mcraw_provider(Confmon * parent)120 Provider* lcb::clconfig::new_mcraw_provider(Confmon* parent) {
121     return new McRawProvider(parent);
122 }
123 
124 struct ClusterAdminProvider : public StaticProvider {
ClusterAdminProviderClusterAdminProvider125     ClusterAdminProvider(Confmon *parent_) : StaticProvider(parent_, CLCONFIG_CLADMIN) {
126     }
127 
gen_configClusterAdminProvider128     lcbvb_CONFIG *gen_config(const lcb::Hostlist& hl) {
129         std::vector<lcbvb_SERVER> servers;
130         servers.reserve(hl.size());
131         for (size_t ii = 0; ii < hl.size(); ++ii) {
132             servers.resize(servers.size() + 1);
133             lcbvb_SERVER& srv = servers[ii];
134             const lcb_host_t& curhost = hl[ii];
135             srv.hostname = const_cast<char*>(curhost.host);
136             if (parent->settings->sslopts) {
137                 srv.svc_ssl.mgmt = std::atoi(curhost.port);
138             } else {
139                 srv.svc.mgmt = std::atoi(curhost.port);
140             }
141         }
142         lcbvb_CONFIG *vbc = lcbvb_create();
143         lcbvb_genconfig_ex(vbc, "NOBUCKET", "deadbeef", &servers[0], servers.size(), 0, 0);
144         return vbc;
145     }
146 };
147 
new_cladmin_provider(Confmon * parent)148 Provider* lcb::clconfig::new_cladmin_provider(Confmon *parent) {
149     return new ClusterAdminProvider(parent);
150 }
151