void QuotaWidget::setQuotaInfo(const QuotaInfo &info) { // we are assuming only to get STORAGE type info here, thus // casting to int is safe int current = info.current().toInt(); int max = info.max().toInt(); mProgressBar->setProgress(current, max); mInfoLabel->setText(info.toString()); mRootLabel->setText(info.root()); }
Future<http::Response> Master::QuotaHandler::_set( const QuotaInfo& quotaInfo, bool forced) const { if (forced) { VLOG(1) << "Using force flag to override quota capacity heuristic check"; } else { // Validate whether a quota request can be satisfied. Option<Error> error = capacityHeuristic(quotaInfo); if (error.isSome()) { return Conflict( "Heuristic capacity check for set quota request failed: " + error.get().message); } } Quota quota = Quota{quotaInfo}; // Populate master's quota-related local state. We do this before updating // the registry in order to make sure that we are not already trying to // satisfy a request for this role (since this is a multi-phase event). // NOTE: We do not need to remove quota for the role if the registry update // fails because in this case the master fails as well. master->quotas[quotaInfo.role()] = quota; // Update the registry with the new quota and acknowledge the request. return master->registrar->apply(Owned<Operation>( new quota::UpdateQuota(quotaInfo))) .then(defer(master->self(), [=](bool result) -> Future<http::Response> { // See the top comment in "master/quota.hpp" for why this check is here. CHECK(result); master->allocator->setQuota(quotaInfo.role(), quota); // Rescind outstanding offers to facilitate satisfying the quota request. // NOTE: We set quota before we rescind to avoid a race. If we were to // rescind first, then recovered resources may get allocated again // before our call to `setQuota` was handled. // The consequence of setting quota first is that (in the hierarchical // allocator) it will trigger an allocation. This means the rescinded // offer resources will only be available to quota once another // allocation is invoked. // This can be resolved in the future with an explicit allocation call, // and this solution is preferred to having the race described earlier. rescindOffers(quotaInfo); return OK(); })); }
Future<http::Response> Master::QuotaHandler::set( const http::Request& request) const { VLOG(1) << "Setting quota from request: '" << request.body << "'"; // Authenticate the request. Result<Credential> credential = master->http.authenticate(request); if (credential.isError()) { return Unauthorized("Mesos master", credential.error()); } // Check that the request type is POST which is guaranteed by the master. CHECK_EQ("POST", request.method); // Validate request and extract JSON. // TODO(alexr): Create a type (e.g. a protobuf) for the request JSON. If we // move the `force` field out of the request JSON, we can reuse `QuotaInfo`. Try<JSON::Object> parse = JSON::parse<JSON::Object>(request.body); if (parse.isError()) { return BadRequest( "Failed to parse set quota request JSON '" + request.body + "': " + parse.error()); } Result<JSON::Array> resourcesJSON = parse.get().find<JSON::Array>("resources"); if (resourcesJSON.isError()) { // An `Error` usually indicates that a search string is malformed // (which is not the case here), however it may also indicate that // the `resources` field is not an array. return BadRequest( "Failed to extract 'resources' from set quota request JSON '" + request.body + "': " + resourcesJSON.error()); } if (resourcesJSON.isNone()) { return BadRequest( "Failed to extract 'resources' from set quota request JSON '" + request.body + "': Field is missing"); } // Create protobuf representation of resources. Try<RepeatedPtrField<Resource>> resources = ::protobuf::parse<RepeatedPtrField<Resource>>(resourcesJSON.get()); if (resources.isError()) { return BadRequest( "Failed to parse 'resources' from set quota request JSON '" + request.body + "': " + resources.error()); } // Create the `QuotaInfo` protobuf message from the request JSON. Try<QuotaInfo> create = createQuotaInfo(resources.get()); if (create.isError()) { return BadRequest( "Failed to create 'QuotaInfo' from set quota request JSON '" + request.body + "': " + create.error()); } QuotaInfo quotaInfo = create.get(); // Check that the `QuotaInfo` is a valid quota request. Try<Nothing> validate = quota::validation::quotaInfo(quotaInfo); if (validate.isError()) { return BadRequest( "Failed to validate set quota request JSON '" + request.body + "': " + validate.error()); } // Check that the role is on the role whitelist, if it exists. if (!master->isWhitelistedRole(quotaInfo.role())) { return BadRequest( "Failed to validate set quota request JSON '" + request.body + "': Unknown role '" + quotaInfo.role() + "'"); } // Check that we are not updating an existing quota. // TODO(joerg84): Update error message once quota update is in place. if (master->quotas.contains(quotaInfo.role())) { return BadRequest( "Failed to validate set quota request JSON '" + request.body + "': Can not set quota for a role that already has quota"); } // The force flag can be used to overwrite the `capacityHeuristic` check. Result<JSON::Boolean> force = parse.get().find<JSON::Boolean>("force"); if (force.isError()) { // An `Error` usually indicates that a search string is malformed // (which is not the case here), however it may also indicate that // the `force` field is not a boolean. return BadRequest( "Failed to extract 'force' from set quota request JSON '" + request.body + "': " + force.error()); } // Extract principal from request credentials. Option<string> principal = None(); if (credential.isSome()) { principal = credential.get().principal(); quotaInfo.set_principal(principal.get()); } const bool forced = force.isSome() ? force.get().value : false; return authorizeSetQuota(principal, quotaInfo.role()) .then(defer(master->self(), [=](bool authorized) -> Future<http::Response> { if (!authorized) { return Unauthorized("Mesos master"); } return _set(quotaInfo, forced); })); }