Exemplo n.º 1
0
EpochCrontabItem::EpochCrontabItem(
  const dynamic& d, boost::local_time::time_zone_ptr tz
) : CrontabItem(tz),
    epoch_sel_(d.getDefault("epoch"), 0, std::numeric_limits<time_t>::max()) {

  if (d.size() != 1) {
    throw runtime_error(
      "Can only have the 'epoch' key: " + folly::toJson(d).toStdString()
    );
  }
}
Exemplo n.º 2
0
Job::Job(const Config& config, const string& name, const dynamic& d)
  : id_(Job::JobNameTable->insert(name)),
    name_(name),
    enabled_(d.getDefault("enabled", true).asBool()),
    owner_(d.getDefault("owner", "").asString().toStdString()),
    levelForTasks_(config.levelForTasks),
    priority_(d.getDefault("priority", 1.0).asDouble()),
    resources_(config.defaultJobResources),
    config_(dynamic::object),
    filters_(config.levels.size()),
    levelForHostPlacement_(StringTable::NotFound),
    backoffSettings_(config.defaultBackoffSettings),
    killOrphanTasksAfter_(config.killOrphanTasksAfter) {

  try {
    if (owner_.empty()) {
      throw BistroException("Job ", name, " missing owner.");
    }

    if (const auto* level_for_tasks_ptr = d.get_ptr("level_for_tasks")) {
      if (!level_for_tasks_ptr->isString()) {
        throw BistroException("'level_for_tasks' must be a string for ", name);
      }
      const auto& str_level_for_tasks =
        level_for_tasks_ptr->asString().toStdString();
      int level_for_tasks = config.levels.lookup(str_level_for_tasks);
      if (level_for_tasks == StringTable::NotFound) {
        throw BistroException("Bad level_for_tasks: ", str_level_for_tasks);
      }
      levelForTasks_ = level_for_tasks;
    }

    auto it = d.find("resources");
    if (it != d.items().end()) {
      if (!it->second.isObject()) {
        throw BistroException("'resources' must be an object for ", name);
      }
      for (const auto& pair : it->second.items()) {
        const auto& name = pair.first.asString().toStdString();
        const int resource_id = config.resourceNames.lookup(name);
        if (resource_id == StringTable::NotFound) {
          throw BistroException("Invalid resource: ", name);
        }
        resources_[resource_id] = pair.second.asInt();
      }
    }

    it = d.find("config");
    if (it != d.items().end()) {
      if (!it->second.isObject()) {
        throw BistroException("'config' must be an object for ", name);
      }
      update(config_, it->second);
    }

    it = d.find("backoff");
    if (it != d.items().end()) {
      if (!it->second.isArray()) {
        throw BistroException("'backoff' must be an array for ", name);
      }
      backoffSettings_ = JobBackoffSettings(it->second);
    }

    it = d.find("filters");
    if (it != d.items().end()) {
      if (!it->second.isObject()) {
        throw BistroException("'filters' must be an object for ", name);
      }
      for (const auto& pair : it->second.items()) {
        const auto& level = pair.first.asString().toStdString();
        const int level_id = config.levels.lookup(level);
        if (level_id == StringTable::NotFound) {
          throw BistroException("Invalid level in filters: ", level);
        }
        filters_[level_id] = JobFilters(pair.second);
      }
    }

    detail::parseKillOrphanTasksAfter(d, &killOrphanTasksAfter_);

    if (auto* ptr = d.get_ptr("version_id")) {
      if (!ptr->isInt()) {
        throw std::runtime_error("'version_id' must be an integer");
      }
      versionID_ = ptr->getInt();
    }

    if (const auto* host_level_ptr = d.get_ptr("level_for_host_placement")) {
      if (!host_level_ptr->isString()) {
        throw BistroException(
          "'level_for_host_placement' must be a string for ", name
        );
      }
      const auto& str_host_level =
        host_level_ptr->asString().toStdString();
      int host_level = config.levels.lookup(str_host_level);
      if (host_level == StringTable::NotFound) {
        throw BistroException(
          "Bad level_for_host_placement: ", str_host_level
        );
      }
      levelForHostPlacement_ = host_level;
    }

    if (const auto* host_ptr = d.get_ptr("host_placement")) {
      if (!host_ptr->isString()) {
        throw BistroException("'host_placement' must be a string for ", name);
      }
      hostPlacement_ = host_ptr->asString().toStdString();
      if (!hostPlacement_.empty()
          && levelForHostPlacement_ != StringTable::NotFound) {
        throw BistroException(
          "It makes no sense to specify both 'level_for_host_placement' and "
          "'host_placement'"
        );
      }
    }

    it = d.find("create_time");
    // Silently ignore non-integers because this isn't critical configuration
    if (it != d.items().end() && it->second.isInt()) {
      createTime_ = it->second.asInt();
    }

    it = d.find("modify_time");
    // Silently ignore non-integers because this isn't critical configuration
    if (it != d.items().end() && it->second.isInt()) {
      modifyTime_ = it->second.asInt();
    }

    // We don't check that the job names in depends_on are valid jobs.
    // If an invalid job is specified here, or if there is circular dependency,
    // this job can never run.
    it = d.find("depends_on");
    if (it != d.items().end()) {
      if (!it->second.isArray()) {
        throw BistroException("'depends_on' must be an array for ", name);
      }
      for (const auto& job_name : it->second) {
        dependsOn_.push_back(static_cast<ID>(JobNameTable->insert(
          job_name.asString().toStdString()
        )));
      }
    }
  } catch (const exception& e) {
    LOG(ERROR) << "Error creating job: " << e.what();
    error_ = e.what();
    enabled_ = false;
  }
}