Exemple #1
0
// GET /
bool ApiRequest::index()
{
	// FIXME: thread safety.
	// In order to make this method thread-safe, we must ensure that each director's 
	// json-write is done from within the director's worker thread and finally
	// the reply be sent to the client from within the request's worker thread.

	Buffer result;
	JsonWriter json(result);

	json.beginObject();
	for (auto di: *directors_) {
		Director* director = di.second;
		json.name(director->name()).value(*director);
	}
	json.endObject();
	result << "\n";

	char slen[32];
	snprintf(slen, sizeof(slen), "%zu", result.size());

	request_->responseHeaders.push_back("Cache-Control", "no-cache");
	request_->responseHeaders.push_back("Content-Type", "application/json");
	request_->responseHeaders.push_back("Access-Control-Allow-Origin", "*");
	request_->responseHeaders.push_back("Content-Length", slen);
	request_->write<BufferSource>(result);
	request_->finish();

	return true;
}
Exemple #2
0
void HealthMonitor::update() {
  Director* director = static_cast<Director*>(backend_->manager());

  setRequest(
      "GET %s HTTP/1.1\r\n"
      "Host: %s\r\n"
      "x0-Health-Check: yes\r\n"
      "x0-Director: %s\r\n"
      "x0-Backend: %s\r\n"
      "\r\n",
      director->healthCheckRequestPath().c_str(),
      director->healthCheckHostHeader().c_str(), director->name().c_str(),
      backend_->name().c_str());
}
Exemple #3
0
void DirectorPlugin::pass(HttpRequest* r, const std::string& directorName,
                          const std::string& backendName) {
    auto i = directors_.find(directorName);
    if (i == directors_.end()) {
        r->log(Severity::error,
               "director.pass(): No director with name '%s' configured.",
               directorName.c_str());
        internalServerError(r);
        return;
    }
    Director* director = i->second.get();

    // custom backend route
    Backend* backend = nullptr;
    if (!backendName.empty()) {
        backend = director->findBackend(backendName);

        if (!backend) {
            // explicit backend specified, but not found -> do not serve.
            r->log(Severity::error, "director: Requested backend '%s' not found.",
                   backendName.c_str());
            internalServerError(r);
            return;
        }
    }

#if !defined(NDEBUG)
    server().log(Severity::trace, "director: passing request to %s [backend %s].",
                 director->name().c_str(), backend->name().c_str());
#endif

    auto rn = requestNotes(r);
    rn->manager = director;

    r->onPostProcess.connect(std::bind(&DirectorPlugin::addVia, this, r));

    director->schedule(rn, backend);

    return;
}
Exemple #4
0
void DirectorPlugin::balance(HttpRequest* r, const std::string& directorName,
                             const std::string& bucketName) {
    auto i = directors_.find(directorName);
    if (i == directors_.end()) {
        r->log(Severity::error,
               "director.balance(): No director with name '%s' configured.",
               directorName.c_str());
        internalServerError(r);
        return;
    }
    Director* director = i->second.get();

    RequestShaper::Node* bucket = nullptr;
    if (!bucketName.empty()) {
        bucket = director->findBucket(bucketName);
        if (!bucket) {
            // explicit bucket specified, but not found -> ignore.
            bucket = director->rootBucket();
            r->log(Severity::error,
                   "director: Requested bucket '%s' not found in director '%s'. "
                   "Assigning root bucket.",
                   bucketName.c_str(), directorName.c_str());
        }
    } else {
        bucket = director->rootBucket();
    }

    auto rn = requestNotes(r);
    rn->manager = director;

    r->onPostProcess.connect(std::bind(&DirectorPlugin::addVia, this, r));

#if !defined(NDEBUG)
    server().log(Severity::trace, "director: passing request to %s [%s].",
                 director->name().c_str(), bucket->name().c_str());
#endif

    director->schedule(rn, bucket);
}  // }}}
Exemple #5
0
void HaproxyApi::csv(HttpRequest* r)
{
	Buffer buf;

	buf.push_back("# pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,\n");

	for (auto di: *directors_) {
		Director* director = di.second;

		buildFrontendCSV(buf, director);

		director->eachBackend([&](Backend* backend) {
			// 01 pxname: proxy name
			buf.push_back(director->name());
			buf.push_back(',');

			// 02 svname: service name (FRONTEND for frontend, BACKEND for backend, any name for server)
			buf.push_back(backend->name()); // svname

			// 03 qcur: current queued requests
			// 04 qmax: max queued requests
			buf.push_back(",0,0,"); // qcur, qmax

			// 05 scur: current sessions
			buf.push_back(backend->load().current());
			buf.push_back(',');

			// 06 smax: max sessions
			buf.push_back(backend->load().max());
			buf.push_back(",");

			// 07 slim: sessions limit
			buf.push_back(",");

			// 08 stot: total sessions
			buf.push_back(backend->load().total());

			// 09 bin: bytes in
			// 10 bout: bytes out
			buf.push_back(",0,0,"); // bin, bout

			// 11 dreq: denied requests
			// 12 dresp: denied responses
			buf.push_back("0,0,"); // dreq, dresp

			// 13 ereq: request errors
			// 14 econ: connection errors
			// 15 eresp: response errors (among which srv_abrt)
			buf.push_back("0,0,0,"); // ereq, econ, resp

			// 16 wretr: retries (warning)
			// 17 wredis: redispatches (warning)
			buf.push_back("0,0,"); // wretr, wredis

			// 18 status
			if (!backend->isEnabled()) { // status
				buf.push_back("MAINT");
			} else if (backend->healthMonitor()) {
				switch (backend->healthMonitor()->state()) {
				case HealthState::Online:
					buf.push_back("UP");
					break;
				case HealthState::Offline:
					buf.push_back("DOWN");
					break;
				case HealthState::Undefined:
					buf.push_back("UNKNOWN");
					break;
				}
			} else {
				buf.push_back("UP");
			}

			// weight: server weight (server), total weight (backend)
			buf.push_back(",0,"); // weight

			// 20 act: server is active (server), number of active servers (backend)
			// 21 bck: server is backup (server), number of backup servers (backend)
			switch (director->backendRole(backend)) { // act, bck
				case BackendRole::Active:
					buf.push_back("1,0,");
					break;
				case BackendRole::Backup:
					buf.push_back("0,1,");
					break;
				case BackendRole::Terminate:
					buf.push_back("0,0,");
					break;
			}
			// 22 chkfail: number of failed checks
			buf.push_back(','); // TODO

			// 23 chkdown: number of UP->DOWN transitions
			buf.push_back(','); // TODO

			// 24 lastchg: last status change (in seconds)
			buf.push_back(','); // TODO

			// 25 downtime: total downtime (in seconds)
			buf.push_back(','); // TODO

			// 26 qlimit: queue limit
			buf.push_back(',');

			// 27 pid: process id (0 for first instance, 1 for second, ...)
			buf.push_back("0,");

			// 28 iid: unique proxy id
			buf.push_back(',');

			// 29 sid: service id (unique inside a proxy)
			buf.push_back(',');

			// 30 throttle: warm up status
			buf.push_back(',');

			// 31 lbtot: total number of times a server was selected
			buf.push_back(','); // TODO

			// 32 tracked: id of proxy/server if tracking is enabled
			buf.push_back(',');

			// 33 type (0=frontend, 1=backend, 2=server, 3=socket)
			buf.push_back("2,");

			// 34 rate: number of sessions per second over last elapsed second
			buf.push_back(','); // TODO

			// 35 rate_lim: limit on new sessions per second
			buf.push_back(',');

			// 36 rate_max: max number of new sessions per second
			buf.push_back(',');

			// 37 check_status: status of last health check, one of:
			// - UNK -> unknown
			// - INI -> initializing
			// - SOCKERR -> socket error
			// - L4OK -> check passed on layer 4, no upper layers testing enabled
			// - L4TMOUT -> layer 1-4 timeout
			// - L4CON -> layer 1-4 connection problem, for example "Connection refused" (tcp rst) or "No route to host" (icmp)
			// - L6OK -> check passed on layer 6
			// - L6TOUT -> layer 6 (SSL) timeout
			// - L6RSP -> layer 6 invalid response - protocol error
			// - L7OK -> check passed on layer 7
			// - L7OKC -> check conditionally passed on layer 7, for example 404 with disable-on-404
			// - L7TOUT -> layer 7 (HTTP/SMTP) timeout
			// - L7RSP -> layer 7 invalid response - protocol error
			// - L7STS -> layer 7 response error, for example HTTP 5xx
			buf.push_back("UNK,"); // TODO

			// 38 check_code: layer5-7 code, if available
			buf.push_back(',');

			// 39 check_duration: time in ms took to finish last health check
			buf.push_back(','); // TODO

			// 40 hrsp_1xx: http responses with 1xx code
			buf.push_back(','); // TODO

			// 41 hrsp_2xx: http responses with 2xx code
			buf.push_back(','); // TODO

			// 42 hrsp_3xx: http responses with 3xx code
			buf.push_back(','); // TODO

			// 43 hrsp_4xx: http responses with 4xx code
			buf.push_back(','); // TODO

			// 44 hrsp_5xx: http responses with 5xx code
			buf.push_back(','); // TODO

			// 45 hrsp_other: http responses with other codes (protocol error)
			buf.push_back(','); // TODO

			// 46 hanafail: failed health checks details
			buf.push_back(','); // TODO

			// 47 req_rate: HTTP requests per second over last elapsed second
			buf.push_back(',');

			// 48 req_rate_max: max number of HTTP requests per second observed
			buf.push_back(',');

			// 49 req_tot: total number of HTTP requests received
			buf.push_back(backend->load().total());
			buf.push_back(',');

			// 50 cli_abrt: number of data transfers aborted by the client
			buf.push_back(','); // TODO

			// 51 srv_abrt: number of data transfers aborted by the server (inc. in eresp)
			buf.push_back(','); // TODO

			buf.push_back('\n');
		});
	}

	char slen[32];
	snprintf(slen, sizeof(slen), "%zu", buf.size());
	r->responseHeaders.push_back("Content-Length", slen);
	r->responseHeaders.push_back("Content-Type", "text/plain"); // HAproxy software does sent this one instead of text/csv.
	r->responseHeaders.push_back("Cache-Control", "no-cache");
	r->write<x0::BufferSource>(buf);
	r->finish();
}