FailoverWithExptimeRoute::FailoverWithExptimeRoute(
  RouteHandleFactory<McrouterRouteHandleIf>& factory,
  const folly::dynamic& json)
    : failoverExptime_(60) {

  checkLogic(json.isObject(), "FailoverWithExptimeRoute is not object");

  std::vector<McrouterRouteHandlePtr> failoverTargets;

  if (json.count("failover")) {
    failoverTargets = factory.createList(json["failover"]);
  }

  failover_ = FailoverRoute<McrouterRouteHandleIf>(std::move(failoverTargets));

  if (json.count("normal")) {
    normal_ = factory.create(json["normal"]);
  }

  if (json.count("failover_exptime")) {
    checkLogic(json["failover_exptime"].isInt(),
               "failover_exptime is not integer");
    failoverExptime_ = json["failover_exptime"].asInt();
  }

  if (json.count("settings")) {
    settings_ = FailoverWithExptimeSettings(json["settings"]);
  }
}
McrouterRouteHandlePtr makeFailoverWithExptimeRoute(
    RouteHandleFactory<McrouterRouteHandleIf>& factory,
    const folly::dynamic& json) {
  checkLogic(json.isObject(), "FailoverWithExptimeRoute is not an object");

  McrouterRouteHandlePtr normal;
  if (auto jnormal = json.get_ptr("normal")) {
    normal = factory.create(*jnormal);
  }

  std::vector<McrouterRouteHandlePtr> failoverTargets;
  if (auto jfailover = json.get_ptr("failover")) {
    failoverTargets = factory.createList(*jfailover);
  }

  int32_t failoverExptime = 60;
  if (auto jexptime = json.get_ptr("failover_exptime")) {
    checkLogic(jexptime->isInt(), "FailoverWithExptimeRoute: "
                                  "failover_exptime is not an integer");
    failoverExptime = jexptime->getInt();
  }

  // Check if only one format is being used
  checkLogic(!(json.count("settings") && // old
        (json.count("failover_errors") || json.count("failover_tag"))), // new
      "Use either 'settings' (old format) or 'failover_errors' / 'failover_tag'"
    );

  // new format
  FailoverErrorsSettings failoverErrors;
  bool failoverTagging = false;
  if (auto jfailoverTag = json.get_ptr("failover_tag")) {
    checkLogic(jfailoverTag->isBool(),
               "FailoverWithExptime: failover_tag is not bool");
    failoverTagging = jfailoverTag->getBool();
  }
  if (auto jfailoverErrors = json.get_ptr("failover_errors")) {
    failoverErrors = FailoverErrorsSettings(*jfailoverErrors);
  }

  // old format
  if (auto jsettings = json.get_ptr("settings")) {
    VLOG(1) << "FailoverWithExptime: This config format is deprecated. "
               "Use 'failover_errors' instead of 'settings'.";
    auto oldSettings = FailoverWithExptimeSettings(*jsettings);
    failoverTagging = oldSettings.failoverTagging;
    failoverErrors = oldSettings.getFailoverErrors();
  }

  return makeFailoverWithExptimeRoute(
    std::move(normal),
    std::move(failoverTargets),
    failoverExptime,
    std::move(failoverErrors),
    failoverTagging);
}
ProxyConfig::ProxyConfig(proxy_t* proxy,
                         const folly::dynamic& json,
                         std::string configMd5Digest,
                         std::shared_ptr<PoolFactory> poolFactory)
  : poolFactory_(std::move(poolFactory)),
    configMd5Digest_(std::move(configMd5Digest)) {

  McRouteHandleProvider provider(proxy, *proxy->destinationMap, *poolFactory_);
  RouteHandleFactory<McrouterRouteHandleIf> factory(provider);

  checkLogic(json.isObject(), "Config is not an object");

  if (json.count("named_handles")) {
    checkLogic(json["named_handles"].isArray(), "named_handles is not array");
    for (const auto& it : json["named_handles"]) {
      factory.create(it);
    }
  }

  RouteSelectorMap routeSelectors;

  auto jRoute = json.get_ptr("route");
  auto jRoutes = json.get_ptr("routes");
  checkLogic(!jRoute || !jRoutes,
             "Invalid config: both 'route' and 'routes' are specified");
  checkLogic(jRoute || jRoutes, "No route/routes in config");
  if (jRoute) {
    routeSelectors[proxy->getRouterOptions().default_route] =
        std::make_shared<PrefixSelectorRoute>(factory, *jRoute);
  } else { // jRoutes
    checkLogic(jRoutes->isArray() || jRoutes->isObject(),
               "Config: routes is not array/object");
    if (jRoutes->isArray()) {
      for (const auto& it : *jRoutes) {
        checkLogic(it.isObject(), "RoutePolicy is not an object");
        auto jCurRoute = it.get_ptr("route");
        auto jAliases = it.get_ptr("aliases");
        checkLogic(jCurRoute, "RoutePolicy: no route");
        checkLogic(jAliases, "RoutePolicy: no aliases");
        checkLogic(jAliases->isArray(), "RoutePolicy: aliases is not an array");
        auto routeSelector =
            std::make_shared<PrefixSelectorRoute>(factory, *jCurRoute);
        for (const auto& alias : *jAliases) {
          checkLogic(alias.isString(), "RoutePolicy: alias is not a string");
          routeSelectors[alias.stringPiece()] = routeSelector;
        }
      }
    } else { // object
      for (const auto& it : jRoutes->items()) {
        checkLogic(it.first.isString(), "RoutePolicy: alias is not a string");
        routeSelectors[it.first.stringPiece()] =
            std::make_shared<PrefixSelectorRoute>(factory, it.second);
      }
    }
  }

  asyncLogRoutes_ = provider.releaseAsyncLogRoutes();
  proxyRoute_ = std::make_shared<ProxyRoute>(proxy, routeSelectors);
  serviceInfo_ = std::make_shared<ServiceInfo>(proxy, *this);
}
std::vector<double> WeightedChHashFuncBase::parseWeights(
    const folly::dynamic& json,
    size_t n) {
  std::vector<double> weights;
  checkLogic(
      json.isObject() && json.count("weights"),
      "WeightedChHashFunc: not an object or no weights");
  checkLogic(
      json["weights"].isArray(), "WeightedChHashFunc: weights is not array");
  const auto& jWeights = json["weights"];
  LOG_IF(ERROR, jWeights.size() < n)
      << "WeightedChHashFunc: CONFIG IS BROKEN!!! number of weights ("
      << jWeights.size() << ") is smaller than number of servers (" << n
      << "). Missing weights are set to 0.5";
  for (size_t i = 0; i < std::min(n, jWeights.size()); ++i) {
    const auto& weight = jWeights[i];
    checkLogic(weight.isNumber(), "WeightedChHashFunc: weight is not number");
    const auto weightNum = weight.asDouble();
    checkLogic(
        0 <= weightNum && weightNum <= 1.0,
        "WeightedChHashFunc: weight must be in range [0, 1.0]");
    weights.push_back(weightNum);
  }
  weights.resize(n, 0.5);
  return weights;
}
Beispiel #5
0
ProxyConfig::ProxyConfig(proxy_t* proxy,
                         const folly::dynamic& json,
                         std::string configMd5Digest,
                         std::shared_ptr<PoolFactory> poolFactory)
  : poolFactory_(std::move(poolFactory)),
    configMd5Digest_(std::move(configMd5Digest)) {

  McRouteHandleProvider provider(proxy, *proxy->destinationMap, *poolFactory_);
  RouteHandleFactory<McrouterRouteHandleIf> factory(provider);

  checkLogic(json.isObject(), "Config is not an object");

  if (json.count("named_handles")) {
    checkLogic(json["named_handles"].isArray(), "named_handles is not array");
    for (const auto& it : json["named_handles"]) {
      factory.create(it);
    }
  }

  checkLogic(!json.count("route") || !json.count("routes"),
             "Config ambiguous, has both route and routes");

  RouteSelectorMap routeSelectors;

  if (json.count("route")) {
    addRouteSelector({ proxy->opts.default_route.str() },
                     json["route"], factory, routeSelectors);
  } else if (json.count("routes")) {
    checkLogic(json["routes"].isArray(), "Config: routes is not array");
    for (const auto& it : json["routes"]) {
      checkLogic(it.isObject(), "RoutePolicy is not object");
      checkLogic(it.count("route"), "RoutePolicy has no route");
      checkLogic(it.count("aliases"), "RoutePolicy has no aliases");
      const auto& aliases = it["aliases"];
      checkLogic(aliases.isArray(), "RoutePolicy aliases is not array");
      addRouteSelector(aliases, it["route"], factory, routeSelectors);
    }
  } else {
    throw std::logic_error("No route/routes in config");
  }


  asyncLogRoutes_ = provider.releaseAsyncLogRoutes();
  proxyRoute_ = std::make_shared<ProxyRoute>(proxy, routeSelectors);
  serviceInfo_ = std::make_shared<ServiceInfo>(proxy, *this);
}
inline void checkStringField(
    const folly::dynamic& json,
    folly::StringPiece name,
    std::string expected) {
  ASSERT_EQ(1, json.count(name));
  ASSERT_TRUE(json[name].isString());
  EXPECT_EQ(expected, json[name].asString());
}
inline void checkIntField(
    const folly::dynamic& json,
    folly::StringPiece name,
    Type expected) {
  ASSERT_EQ(1, json.count(name));
  ASSERT_TRUE(json[name].isInt());
  EXPECT_EQ(static_cast<int64_t>(expected), json[name].asInt());
}
RateLimiter::RateLimiter(const folly::dynamic& json) {
  checkLogic(json.isObject(), "RateLimiter settings json is not an object");

  auto now = TokenBucket::defaultClockNow();

  if (json.count("gets_rate")) {
    double rate = asPositiveDouble(json, "gets_rate");
    double burst = asPositiveDoubleDefault(json, "gets_burst", rate);
    getsTb_ = TokenBucket(rate, burst, now);
  }

  if (json.count("sets_rate")) {
    double rate = asPositiveDouble(json, "sets_rate");
    double burst = asPositiveDoubleDefault(json, "sets_burst", rate);
    setsTb_ = TokenBucket(rate, burst, now);
  }

  if (json.count("deletes_rate")) {
    double rate = asPositiveDouble(json, "deletes_rate");
    double burst = asPositiveDoubleDefault(json, "deletes_burst", rate);
    deletesTb_ = TokenBucket(rate, burst, now);
  }
}
Beispiel #9
0
std::vector<McrouterRouteHandlePtr> makeShadowRoutes(
    RouteHandleFactory<McrouterRouteHandleIf>& factory,
    const folly::dynamic& json,
    proxy_t& proxy,
    ExtraRouteHandleProviderIf& extraProvider) {
  checkLogic(json.isObject(), "ShadowRoute should be an object");
  const auto jchildren = json.get_ptr("children");
  checkLogic(jchildren, "ShadowRoute: children not found");
  auto children = factory.createList(*jchildren);
  if (json.count("shadows")) {
    children = makeShadowRoutes(
        factory, json, std::move(children), proxy, extraProvider);
  }
  return children;
}
OperationSelectorRoute::OperationSelectorRoute(
    RouteHandleFactory<McrouterRouteHandleIf>& factory,
    const folly::dynamic& json) {
  if (!json.isObject()) {
    defaultPolicy_ = factory.create(json);
    return;
  }

  if (json.count("default_policy")) {
    defaultPolicy_ = factory.create(json["default_policy"]);
  }

  operationPolicies_.resize(mc_nops);
  if (json.count("operation_policies")) {
    const auto& policies = json["operation_policies"];
    checkLogic(policies.isObject(),
               "OperationSelectorRoute: operation_policies is not object");

    std::map<std::string, folly::dynamic> orderedPolicies;
    for (const auto& it : policies.items()) {
      checkLogic(it.first.isString(),
                 "OperationSelectorRoute: operation_policies "
                 "key is not a string");
      auto key = it.first.asString().toStdString();
      orderedPolicies.insert({ key, it.second });
    }

    // order is important here: named handles may not be resolved if we parse
    // policies in random order
    for (const auto& it : orderedPolicies) {
      auto opId = mc_op_from_string(it.first.data());
      checkLogic(opId != mc_op_unknown, "Unknown mc operation: {}", it.first);
      operationPolicies_[opId] = factory.create(it.second);
    }
  }
}
WeightedCh3HashFunc::WeightedCh3HashFunc(const folly::dynamic& json, size_t n) {
  checkLogic(json.isObject() && json.count("weights"),
             "WeightedCh3HashFunc: not an object or no weights");
  checkLogic(json["weights"].isArray(),
             "WeightedCh3HashFunc: weights is not array");
  const auto& jWeights = json["weights"];
  LOG_IF(ERROR, jWeights.size() < n)
    << "WeightedCh3HashFunc: CONFIG IS BROKEN!!! number of weights ("
    << jWeights.size() << ") is smaller than number of servers (" << n
    << "). Missing weights are set to 0.5";
  for (size_t i = 0; i < std::min(n, jWeights.size()); ++i) {
    const auto& weight = jWeights[i];
    checkLogic(weight.isNumber(), "WeightedCh3HashFunc: weight is not number");
    weights_.push_back(weight.asDouble());
  }
  weights_.resize(n, 0.5);
}
McrouterRouteHandlePtr makeOperationSelectorRoute(
    RouteHandleFactory<McrouterRouteHandleIf>& factory,
    const folly::dynamic& json) {
  if (!json.isObject()) {
    return factory.create(json);
  }

  McrouterRouteHandlePtr defaultPolicy;
  if (json.count("default_policy")) {
    defaultPolicy = factory.create(json["default_policy"]);
  }

  std::vector<McrouterRouteHandlePtr> operationPolicies{mc_nops};
  if (auto jOpPolicies = json.get_ptr("operation_policies")) {
    checkLogic(jOpPolicies->isObject(),
               "OperationSelectorRoute: operation_policies is not an object");

    std::map<std::string, const folly::dynamic*> orderedPolicies;
    for (auto& it : jOpPolicies->items()) {
      checkLogic(it.first.isString(),
                 "OperationSelectorRoute: operation_policies' "
                 "key is not a string");
      auto key = it.first.stringPiece().str();
      orderedPolicies.emplace(std::move(key), &it.second);
    }

    // order is important here: named handles may not be resolved if we parse
    // policies in random order
    for (const auto& it : orderedPolicies) {
      auto opId = mc_op_from_string(it.first.data());
      checkLogic(opId != mc_op_unknown, "Unknown mc operation: {}", it.first);
      operationPolicies[opId] = factory.create(*it.second);
    }

    return makeOperationSelectorRoute(std::move(operationPolicies),
                                      std::move(defaultPolicy));
  }

  return defaultPolicy;
}
Beispiel #13
0
SwitchStateFields
SwitchStateFields::fromFollyDynamic(const folly::dynamic& swJson) {
  SwitchStateFields switchState;
  switchState.interfaces = InterfaceMap::fromFollyDynamic(
        swJson[kInterfaces]);
  switchState.ports = PortMap::fromFollyDynamic(swJson[kPorts]);
  switchState.vlans = VlanMap::fromFollyDynamic(swJson[kVlans]);
  switchState.routeTables = RouteTableMap::fromFollyDynamic(
      swJson[kRouteTables]);
  switchState.acls = AclMap::fromFollyDynamic(swJson[kAcls]);
  if (swJson.count(kSflowCollectors) > 0) {
    switchState.sFlowCollectors = SflowCollectorMap::fromFollyDynamic(
      swJson[kSflowCollectors]);
  }
  switchState.defaultVlan = VlanID(swJson[kDefaultVlan].asInt());
  if (swJson.find(kControlPlane) != swJson.items().end()) {
    switchState.controlPlane = ControlPlane::fromFollyDynamic(
      swJson[kControlPlane]);
  }
  //TODO verify that created state here is internally consistent t4155406
  return switchState;
}
McrouterRouteHandlePtr McRouteHandleProvider::makePoolRoute(
  McRouteHandleFactory& factory, const folly::dynamic& json) {

  checkLogic(json.isObject() || json.isString(),
             "PoolRoute should be object or string");
  const folly::dynamic* jpool;
  if (json.isObject()) {
    jpool = json.get_ptr("pool");
    checkLogic(jpool, "PoolRoute: pool not found");
  } else {
    jpool = &json;
  }
  auto p = makePool(*jpool);
  auto pool = std::move(p.first);
  auto destinations = std::move(p.second);

  if (json.isObject()) {
    if (auto maxOutstandingPtr = json.get_ptr("max_outstanding")) {
      checkLogic(maxOutstandingPtr->isInt(),
                 "PoolRoute {}: max_outstanding is not int", pool->getName());
      auto maxOutstanding = maxOutstandingPtr->asInt();
      if (maxOutstanding) {
        for (auto& destination: destinations) {
          destination = makeOutstandingLimitRoute(std::move(destination),
                                                  maxOutstanding);
        }
      }
    }
  }

  if (json.isObject() && json.count("shadows")) {
    folly::StringPiece shadowPolicy = "default";
    if (auto jshadow_policy = json.get_ptr("shadow_policy")) {
      checkLogic(jshadow_policy->isString(),
                 "PoolRoute: shadow_policy is not a string");
      shadowPolicy = jshadow_policy->stringPiece();
    }

    McrouterShadowData data;
    for (auto& shadow : json["shadows"]) {
      checkLogic(shadow.count("target"),
                 "PoolRoute {} shadows: no target for shadow", pool->getName());
      auto s = ShadowSettings::create(shadow, proxy_->router());
      if (s) {
        data.emplace_back(factory.create(shadow["target"]), std::move(s));
      }
    }

    for (size_t i = 0; i < destinations.size(); ++i) {
      McrouterShadowData destinationShadows;
      for (const auto& shadowData : data) {
        if (shadowData.second->startIndex() <= i &&
            i < shadowData.second->endIndex()) {
          destinationShadows.push_back(shadowData);
        }
      }
      if (!destinationShadows.empty()) {
        destinationShadows.shrink_to_fit();
        destinations[i] = extraProvider_->makeShadow(
          proxy_, std::move(destinations[i]),
          std::move(destinationShadows), shadowPolicy);
      }
    }
  }

  // add weights and override whatever we have in PoolRoute::hash
  folly::dynamic jhashWithWeights = folly::dynamic::object();
  if (pool->getWeights()) {
    jhashWithWeights = folly::dynamic::object
      ("hash_func", WeightedCh3HashFunc::type())
      ("weights", *pool->getWeights());
  }

  if (json.isObject()) {
    if (auto jhash = json.get_ptr("hash")) {
      checkLogic(jhash->isObject() || jhash->isString(),
                 "PoolRoute {}: hash is not object/string", pool->getName());
      if (jhash->isString()) {
        jhashWithWeights["hash_func"] = *jhash;
      } else { // object
        for (const auto& it : jhash->items()) {
          jhashWithWeights[it.first] = it.second;
        }
      }
    }
  }
  auto route = makeHashRoute(jhashWithWeights, std::move(destinations));

  if (json.isObject()) {
    if (proxy_->router().opts().destination_rate_limiting) {
      if (auto jrates = json.get_ptr("rates")) {
        route = makeRateLimitRoute(std::move(route), RateLimiter(*jrates));
      }
    }

    if (auto jsplits = json.get_ptr("shard_splits")) {
      route = makeShardSplitRoute(std::move(route), ShardSplitter(*jsplits));
    }
  }

  auto asynclogName = pool->getName();
  bool needAsynclog = true;
  if (json.isObject()) {
    if (auto jasynclog = json.get_ptr("asynclog")) {
      checkLogic(jasynclog->isBool(), "PoolRoute: asynclog is not bool");
      needAsynclog = jasynclog->getBool();
    }
    if (auto jname = json.get_ptr("name")) {
      checkLogic(jname->isString(), "PoolRoute: name is not a string");
      asynclogName = jname->stringPiece().str();
    }
  }
  if (needAsynclog) {
    route = createAsynclogRoute(std::move(route), asynclogName);
  }

  return route;
}