public function getDeployMessage() { $dbServer = DBServer::LoadByID($this->serverId); $application = Scalr_Dm_Application::init()->loadById($this->applicationId); $source = $application->getSource(); $msgSource = new stdClass(); $msgSource->url = $source->url; $msgSource->type = $source->type; switch ($source->authType) { case Scalr_Dm_Source::AUTHTYPE_PASSWORD: $msgSource->login = $source->getAuthInfo()->login; $msgSource->password = $source->getAuthInfo()->password; break; case Scalr_Dm_Source::AUTHTYPE_CERT: $msgSource->sshPrivateKey = $source->getAuthInfo()->sshPrivateKey; break; } $params['remote_path'] = $this->remotePath; // Prepare keys array and array with values for replacement in script $keys = array_keys($params); $f = create_function('$item', 'return "%".$item."%";'); $keys = array_map($f, $keys); $values = array_values($params); // Generate script contents $preDeployScriptContents = str_replace($keys, $values, $application->getPreDeployScript()); $preDeployScriptContents = str_replace('\\%', "%", $preDeployScriptContents); $postDeployScriptContents = str_replace($keys, $values, $application->getPostDeployScript()); $postDeployScriptContents = str_replace('\\%', "%", $postDeployScriptContents); return new Scalr_Messaging_Msg_Deploy($this->id, $this->remotePath, $msgSource, $preDeployScriptContents, $postDeployScriptContents); }
public function xRemoveApplicationsAction() { $this->request->defineParams(array('applicationId' => array('type' => 'int'))); $application = Scalr_Dm_Application::init()->loadById($this->getParam('applicationId')); $this->user->getPermissions()->validate($application); $application->delete(); $this->response->success(); }
public function DmApplicationCreate($Name, $SourceID, $PreDeployScript = null, $PostDeployScript = null) { $this->restrictAccess(Acl::RESOURCE_DEPLOYMENTS_APPLICATIONS); $application = Scalr_Model::init(Scalr_Model::DM_APPLICATION); $application->envId = $this->Environment->id; if (Scalr_Dm_Application::getIdByNameAndSource($Name, $SourceID)) { throw new Exception("Application already exists in database"); } $application->name = $Name; $application->sourceId = $SourceID; $application->setPreDeployScript($PreDeployScript); $application->setPostDeployScript($PostDeployScript); $application->save(); $response = $this->CreateInitialResponse(); $response->ApplicationID = $application->id; return $response; }
public function extendMessage(Scalr_Messaging_Msg $message, DBServer $dbServer) { if (in_array(ROLE_BEHAVIORS::BASE, $message->handlers)) { return $message; } if ($dbServer->farmRoleId) { $dbFarmRole = DBFarmRole::LoadByID($dbServer->farmRoleId); } switch (get_class($message)) { case "Scalr_Messaging_Msg_BeforeHostTerminate": //Storage try { if ($dbFarmRole) { $storage = new FarmRoleStorage($dbFarmRole); $volumes = $storage->getVolumesConfigs($dbServer, false); if (!empty($volumes)) { $message->volumes = $volumes; } } } catch (Exception $e) { $this->logger->error(new FarmLogMessage($dbServer->farmId, "Cannot init storage: {$e->getMessage()}")); } break; case "Scalr_Messaging_Msg_HostInit": $configuration = $this->getBaseConfiguration($dbServer, true, true); $message->base = $configuration->base; break; case "Scalr_Messaging_Msg_HostInitResponse": //Deployments try { if ($dbFarmRole) { $appId = $dbFarmRole->GetSetting(self::ROLE_DM_APPLICATION_ID); if ($appId) { $application = Scalr_Dm_Application::init()->loadById($appId); $deploymentTask = Scalr_Dm_DeploymentTask::init(); $deploymentTask->create($dbServer->farmRoleId, $appId, $dbServer->serverId, Scalr_Dm_DeploymentTask::TYPE_AUTO, $dbFarmRole->GetSetting(self::ROLE_DM_REMOTE_PATH), $dbServer->envId, Scalr_Dm_DeploymentTask::STATUS_DEPLOYING); $message->deploy = $deploymentTask->getDeployMessageProperties(); } } } catch (Exception $e) { $this->logger->error(new FarmLogMessage($dbServer->farmId, "Cannot init deployment: {$e->getMessage()}")); } $configuration = $this->getBaseConfiguration($dbServer, true); if ($configuration->volumes) { $message->volumes = $configuration->volumes; } $message->base = $configuration->base; break; } $message->handlers[] = ROLE_BEHAVIORS::BASE; return $message; }
public function extendMessage(Scalr_Messaging_Msg $message, DBServer $dbServer) { if (in_array(ROLE_BEHAVIORS::BASE, $message->handlers)) { return $message; } if ($dbServer->farmRoleId) { $dbFarmRole = DBFarmRole::LoadByID($dbServer->farmRoleId); } switch (get_class($message)) { case "Scalr_Messaging_Msg_BeforeHostTerminate": //Storage try { if ($dbFarmRole) { $storage = new FarmRoleStorage($dbFarmRole); $volumes = $storage->getVolumesConfigs($dbServer->index); if (!empty($volumes)) { $message->volumes = $volumes; } } } catch (Exception $e) { $this->logger->error(new FarmLogMessage($dbServer->farmId, "Cannot init storage: {$e->getMessage()}")); } break; case "Scalr_Messaging_Msg_HostInitResponse": //Deployments try { if ($dbFarmRole) { $appId = $dbServer->GetFarmRoleObject()->GetSetting(self::ROLE_DM_APPLICATION_ID); if (!$message->deploy && $appId) { $application = Scalr_Dm_Application::init()->loadById($appId); $deploymentTask = Scalr_Dm_DeploymentTask::init(); $deploymentTask->create($dbServer->farmRoleId, $appId, $dbServer->serverId, Scalr_Dm_DeploymentTask::TYPE_AUTO, $dbFarmRole->GetSetting(self::ROLE_DM_REMOTE_PATH), $dbServer->envId, Scalr_Dm_DeploymentTask::STATUS_DEPLOYING); $message->deploy = $deploymentTask->getDeployMessageProperties(); } } } catch (Exception $e) { $this->logger->error(new FarmLogMessage($dbServer->farmId, "Cannot init deployment: {$e->getMessage()}")); } //Storage try { if ($dbFarmRole) { $storage = new FarmRoleStorage($dbFarmRole); $volumes = $storage->getVolumesConfigs($dbServer->index); if (!empty($volumes)) { $message->volumes = $volumes; } } } catch (Exception $e) { $this->logger->error(new FarmLogMessage($dbServer->farmId, "Cannot init storage: {$e->getMessage()}")); } // Base try { if ($dbFarmRole) { $scriptingLogTimeout = $dbFarmRole->GetSetting(self::ROLE_BASE_KEEP_SCRIPTING_LOGS_TIME); if (!$scriptingLogTimeout) { $scriptingLogTimeout = 3600; } $message->base = new stdClass(); $message->base->keepScriptingLogsTime = $scriptingLogTimeout; $hostNameFormat = $dbFarmRole->GetSetting(self::ROLE_BASE_HOSTNAME_FORMAT); $message->base->hostname = !empty($hostNameFormat) ? $dbServer->applyGlobalVarsToValue($hostNameFormat) : ''; } //keep_scripting_logs_time } catch (Exception $e) { } break; } $message->handlers[] = ROLE_BEHAVIORS::BASE; return $message; }
/** * * @param array $farmSettings * @param array $roles * @return bool */ private function isFarmConfigurationValid($farmId, $farmSettings, array $roles = array()) { $this->errors = array('error_count' => 0); $farmVariables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), Scalr_Scripting_GlobalVariables::SCOPE_FARM); $farmRoleVariables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), Scalr_Scripting_GlobalVariables::SCOPE_FARMROLE); $name = $this->request->stripValue($farmSettings['name']); if (empty($name)) { $this->setBuildError('name', 'Farm name is invalid'); } if ($farmSettings['variables']) { $result = $farmVariables->validateValues(is_array($farmSettings['variables']) ? $farmSettings['variables'] : [], 0, $farmId); if ($result !== TRUE) { $this->setBuildError('variables', $result); } } if (is_numeric($farmSettings['owner'])) { try { $u = (new Scalr_Account_User())->loadById($farmSettings['owner']); if ($u->getAccountId() != $this->user->getAccountId()) { throw new Exception('User not found'); } } catch (Exception $e) { $this->setBuildError('owner', $e->getMessage()); } } if (is_numeric($farmSettings['teamOwner']) && $farmSettings['teamOwner'] > 0) { if ($this->user->canManageAcl()) { $teams = $this->db->getAll('SELECT id, name FROM account_teams WHERE account_id = ?', array($this->user->getAccountId())); } else { $teams = $this->user->getTeams(); } if (!in_array($farmSettings['teamOwner'], array_map(function ($t) { return $t['id']; }, $teams))) { if ($this->db->GetOne('SELECT team_id FROM farms WHERE id = ?', [$farmId]) != $farmSettings['teamOwner']) { $this->setBuildError('teamOwner', 'Team not found'); } } } if (!empty($roles)) { $hasVpcRouter = false; $vpcRouterRequired = false; foreach ($roles as $role) { $dbRole = DBRole::loadById($role['role_id']); try { $dbRole->__getNewRoleObject()->getImage($role['platform'], $role['cloud_location']); } catch (Exception $e) { $this->setBuildError($dbRole->name, sprintf("Role '%s' is not available in %s on %s", $dbRole->name, $role['platform'], $role['cloud_location'])); } if ($role['alias']) { if (!preg_match("/^[A-Za-z0-9]+[A-Za-z0-9-]*[A-Za-z0-9]+\$/si", $role['alias'])) { $this->setBuildError('alias', sprintf(_("Alias for role '%s' should start and end with letter or number and contain only letters, numbers and dashes."), $dbRole->name, $role['platform'], $role['cloud_location']), $role['farm_role_id']); } } // Validate deployments $appId = $role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID]; if ($appId) { $application = Scalr_Dm_Application::init()->loadById($appId); $this->user->getPermissions()->validate($application); if (!$role[Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH]) { $this->setBuildError(Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH, sprintf("Remote path required for deployment on role '%s'", $dbRole->name), $role['farm_role_id']); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { $hasVpcRouter = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES] = $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] = (int) $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO]; if ($role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] < 1 || $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] > 100) { $this->setBuildError(Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO, sprintf("Nodes ratio for RabbitMq role '%s' should be between 1 and 100", $dbRole->name), $role['farm_role_id']); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE] == 'ebs') { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] < 10 || $role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] > 1000) { $this->setBuildError(Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE, sprintf("EBS size for mongoDB role should be between 10 and 1000 GB", $dbRole->name), $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::NGINX)) { $proxies = (array) @json_decode($role['settings'][Scalr_Role_Behavior_Nginx::ROLE_PROXIES], true); foreach ($proxies as $proxyIndex => $proxy) { if ($proxy['ssl'] == 1) { if (empty($proxy['ssl_certificate_id'])) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'SSL certificate is required', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); break; } if ($proxy['port'] == $proxy['ssl_port']) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'HTTP and HTTPS ports cannot be the same', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); } } if (count($proxy['backends']) > 0) { foreach ($proxy['backends'] as $backend) { if (empty($backend['farm_role_id']) && empty($backend['farm_role_alias']) && empty($backend['host'])) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'Destination is required', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); break; } } } } } /* Validate scaling */ $minCount = (int) $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; if (!$minCount && $minCount != 0) { $minCount = 1; } if ($minCount < 0 || $minCount > 400) { $this->setBuildError(DBFarmRole::SETTING_SCALING_MIN_INSTANCES, sprintf(_("Min instances for '%s' must be a number between 0 and 400"), $dbRole->name), $role['farm_role_id']); } $maxCount = (int) $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES]; if (!$maxCount) { $maxCount = 1; } if ($maxCount < 1 || $maxCount > 400) { $this->setBuildError(DBFarmRole::SETTING_SCALING_MAX_INSTANCES, sprintf(_("Max instances for '%s' must be a number between 1 and 400"), $dbRole->name), $role['farm_role_id']); } if ($maxCount < $minCount) { $this->setBuildError(DBFarmRole::SETTING_SCALING_MAX_INSTANCES, sprintf(_("Max instances should be greater or equal than Min instances for role '%s'"), $dbRole->name), $role['farm_role_id']); } if (isset($role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL]) && $role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL] > 0) { $polling_interval = (int) $role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL]; } else { $polling_interval = 2; } if ($polling_interval < 1 || $polling_interval > 50) { $this->setBuildError(DBFarmRole::SETTING_SCALING_POLLING_INTERVAL, sprintf(_("Polling interval for role '%s' must be a number between 1 and 50"), $dbRole->name), $role['farm_role_id']); } /** Validate platform specified settings **/ switch ($role['platform']) { case SERVER_PLATFORMS::EC2: if ($role['settings'][DBFarmRole::SETTING_AWS_TAGS_LIST]) { $reservedBaseCustomTags = ['scalr-meta', 'Name']; $baseCustomTags = @explode("\n", $role['settings'][DBFarmRole::SETTING_AWS_TAGS_LIST]); foreach ((array) $baseCustomTags as $tag) { $tag = trim($tag); $tagChunks = explode("=", $tag); if (in_array(trim($tagChunks[0]), $reservedBaseCustomTags)) { $this->setBuildError(DBFarmRole::SETTING_AWS_TAGS_LIST, "Avoid using Scalr-reserved tag names.", $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MYSQL)) { if ($role['settings'][DBFarmRole::SETTING_MYSQL_DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if ($dbRole->generation != 2) { if ($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == "" || $role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == "x-scalr-diff" || stristr($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE], 'x-scalr-custom')) { $this->setBuildError(DBFarmRole::SETTING_AWS_AVAIL_ZONE, sprintf(_("Requirement for EBS MySQL data storage is specific 'Placement' parameter for role '%s'"), $dbRole->name), $role['farm_role_id']); } } } } if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EPH) { if (!$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISK] && !$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISKS]) { $this->setBuildError(Scalr_Db_Msr::DATA_STORAGE_EPH_DISK, sprintf(_("Ephemeral disk settings is required for role '%s'"), $dbRole->name), $role['farm_role_id']); } } if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::LVM) { if (!$role['settings'][Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES]) { $this->setBuildError(Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES, sprintf(_("LVM storage settings is required for role '%s'"), $dbRole->name), $role['farm_role_id']); } } } if ($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == 'x-scalr-custom=') { $this->setBuildError(DBFarmRole::SETTING_AWS_AVAIL_ZONE, sprintf(_("Availability zone for role \"%s\" should be selected"), $dbRole->name), $role['farm_role_id']); } if ($farmSettings['vpc_id']) { $sgs = @json_decode($role['settings'][DBFarmRole::SETTING_AWS_SECURITY_GROUPS_LIST]); if (!$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER) && empty($sgs) && !$role['settings'][DBFarmRole::SETTING_AWS_SG_LIST] && !$role['settings']['aws.security_group']) { $this->setBuildError(DBFarmRole::SETTING_AWS_SECURITY_GROUPS_LIST, 'Security group(s) should be selected', $role['farm_role_id']); } $subnets = @json_decode($role['settings'][DBFarmRole::SETTING_AWS_VPC_SUBNET_ID]); if (empty($subnets)) { $this->setBuildError(DBFarmRole::SETTING_AWS_VPC_SUBNET_ID, 'VPC Subnet(s) should be selected', $role['farm_role_id']); } if (\Scalr::config('scalr.instances_connection_policy') != 'local' && !$role['settings'][Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID] && !$vpcRouterRequired) { try { $subnets = @json_decode($role['settings'][DBFarmRole::SETTING_AWS_VPC_SUBNET_ID]); if ($subnets[0]) { $platform = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); $info = $platform->listSubnets($this->getEnvironment(), $role['cloud_location'], $farmSettings['vpc_id'], true, $subnets[0]); if ($info && $info['type'] == 'private') { $vpcRouterRequired = $role['farm_role_id']; } } } catch (Exception $e) { } } } break; case SERVER_PLATFORMS::CLOUDSTACK: if (!$role['settings'][DBFarmRole::SETTING_CLOUDSTACK_SERVICE_OFFERING_ID]) { $this->setBuildError(DBFarmRole::SETTING_CLOUDSTACK_SERVICE_OFFERING_ID, sprintf(_("Service offering for '%s' cloudstack role should be selected on 'Cloudstack settings' tab"), $dbRole->name), $role['farm_role_id']); } break; case SERVER_PLATFORMS::RACKSPACE: if (!$role['settings'][DBFarmRole::SETTING_RS_FLAVOR_ID]) { $this->setBuildError(DBFarmRole::SETTING_CLOUDSTACK_SERVICE_OFFERING_ID, sprintf(_("Flavor for '%s' rackspace role should be selected on 'Placement and type' tab"), $dbRole->name), $role['farm_role_id']); } break; } if ($role['settings'][Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS] && PlatformFactory::isOpenstack($role['platform'])) { $reservedBaseCustomTags = ['scalr-meta', 'farmid', 'role', 'httpproto', 'region', 'hash', 'realrolename', 'szr_key', 'serverid', 'p2p_producer_endpoint', 'queryenv_url', 'behaviors', 'farm_roleid', 'roleid', 'env_id', 'platform', 'server_index', 'cloud_server_id', 'cloud_location_zone', 'owner_email']; $baseCustomTags = @explode("\n", $role['settings'][Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS]); foreach ((array) $baseCustomTags as $tag) { $tag = trim($tag); $tagChunks = explode("=", $tag); if (in_array(trim($tagChunks[0]), $reservedBaseCustomTags)) { $this->setBuildError(Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS, "Avoid using Scalr-reserved metadata names.", $role['farm_role_id']); } } } if ($role['settings'][Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT]) { if (!preg_match('/^[A-Za-z0-9\\{\\}_\\.-]+$/si', $role['settings'][Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT])) { $this->setBuildError(Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT, "server hostname format for role'{$dbRole->name}' should contain only [a-z0-9-] chars. First char should not be hypen.", $role['farm_role_id']); } } if ($role['settings'][DBFarmRole::SETTING_DNS_CREATE_RECORDS]) { if ($role['settings'][DBFarmRole::SETTING_DNS_EXT_RECORD_ALIAS]) { if (!preg_match('/^[A-Za-z0-9\\{\\}_\\.-]+$/si', $role['settings'][DBFarmRole::SETTING_DNS_EXT_RECORD_ALIAS])) { $this->setBuildError(DBFarmRole::SETTING_DNS_EXT_RECORD_ALIAS, "ext- record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not be hypen.", $role['farm_role_id']); } } if ($role['settings'][DBFarmRole::SETTING_DNS_INT_RECORD_ALIAS]) { if (!preg_match('/^[A-Za-z0-9\\{\\}_\\.-]+$/si', $role['settings'][DBFarmRole::SETTING_DNS_INT_RECORD_ALIAS])) { $this->setBuildError(DBFarmRole::SETTING_DNS_INT_RECORD_ALIAS, "int- record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not by hypen.", $role['farm_role_id']); } } } //DEPRECATED $rParams = $dbRole->getParameters(); if (count($rParams) > 0 && strpos($role['farm_role_id'], 'virtual_') === false) { if (empty($role['params'])) { try { $dbFarmRole = DBFarmRole::LoadByID($role['farm_role_id']); foreach ($rParams as $param) { $farmRoleOption = $this->db->GetRow("SELECT id, value FROM farm_role_options WHERE farm_roleid=? AND `hash`=? LIMIT 1", array($dbFarmRole->ID, $param['hash'])); if ($farmRoleOption['id']) { $value = $farmRoleOption['value']; } $role['params'][$param['hash']] = $value; } } catch (Exception $e) { } } } //Validate role parameters foreach ($rParams as $p) { if ($p['required'] && $role['params'][$p['hash']] == "" && !$p['defval']) { $this->setBuildError($p['name'], "Missed required parameter '{$p['name']}' for role '{$dbRole->name}'", $role['farm_role_id']); } } // Validate Global variables if (!strstr($role['farm_role_id'], 'virtual_')) { $farmRole = DBFarmRole::LoadByID($role['farm_role_id']); } else { $farmRole = null; } $result = $farmRoleVariables->validateValues(is_array($role['variables']) ? $role['variables'] : [], $dbRole->id, $farmId, $farmRole ? $farmRole->ID : 0); if ($result !== TRUE) { $this->setBuildError('variables', $result, $role['farm_role_id']); } } } if ($farmSettings['vpc_id']) { if (!$hasVpcRouter && $vpcRouterRequired) { $this->setBuildError(DBFarmRole::SETTING_AWS_VPC_SUBNET_ID, 'You must select a VPC Router for Farm Roles launched in a Private VPC Subnet', $vpcRouterRequired); } } if ($this->getContainer()->analytics->enabled && $this->request->isInterfaceBetaOrNotHostedScalr()) { if ($farmSettings['projectId']) { $project = $this->getContainer()->analytics->projects->get($farmSettings['projectId']); if (!$project) { $this->setBuildError('projectId', 'Project not found', null); } else { if ($project->ccId != $this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)) { $this->setBuildError('projectId', 'Invalid project identifier. Project should correspond to the Environment\'s cost center.', null); } } } else { $this->setBuildError('projectId', 'Project field is required', null); } } return $this->errors['error_count'] == 0 ? true : false; }
public function xBuildAction() { $this->request->defineParams(array('farmId' => array('type' => 'int'), 'roles' => array('type' => 'json'), 'farm' => array('type' => 'json'), 'roleUpdate' => array('type' => 'int'))); $Validator = new Validator(); $cloudFoundryStack = array(); $nginxFound = 0; foreach ($this->getParam('roles') as $role) { $dbRole = DBRole::loadById($role['role_id']); if (!$dbRole->getImageId($role['platform'], $role['cloud_location'])) { throw new Exception(sprintf(_("Role '%s' is not available in %s on %s"), $dbRole->name, $role['platform'], $role['cloud_location'])); } // Validate deployments $appId = $role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID]; if ($appId) { $application = Scalr_Dm_Application::init()->loadById($appId); $this->user->getPermissions()->validate($application); if (!$role[Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH]) { throw new Exception(sprintf("Remote path reuired for deployment on role '%s'", $dbRole->name)); } } //-- CloudFoundryStuff if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_DEA)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_DEA] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_HEALTH_MANAGER)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_HEALTH_MANAGER] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_ROUTER)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_ROUTER] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_SERVICE)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_SERVICE] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::NGINX)) { $nginxFound++; } //-- End CloudFoundry stuff if ($dbRole->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES] = $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] = (int) $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO]; if ($role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] < 1 || $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] > 100) { throw new Exception(sprintf("Nodes ratio for RabbitMq role '%s' should be between 1 and 100", $dbRole->name)); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE] == 'ebs') { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] < 10 || $role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] > 1000) { throw new Exception(sprintf("EBS size for mongoDB role should be between 10 and 1000 GB", $dbRole->name)); } } } /* Validate scaling */ $minCount = (int) $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; if (!$minCount && $minCount != 0) { $minCount = 1; } if ($minCount < 0 || $minCount > 400) { throw new Exception(sprintf(_("Min instances for '%s' must be a number between 1 and 400"), $dbRole->name)); } $maxCount = (int) $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES]; if (!$maxCount) { $maxCount = 1; } if ($maxCount < 1 || $maxCount > 400) { throw new Exception(sprintf(_("Max instances for '%s' must be a number between 1 and 400"), $dbRole->name)); } if ($maxCount < $minCount) { throw new Exception(sprintf(_("Max instances should be greater or equal than Min instances for role '%s'"), $dbRole->name)); } if (isset($role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL]) && $role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL] > 0) { $polling_interval = (int) $role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL]; } else { $polling_interval = 2; } if ($polling_interval < 1 || $polling_interval > 50) { throw new Exception(sprintf(_("Polling interval for role '%s' must be a number between 1 and 50"), $dbRole->name)); } /** Validate platform specified settings **/ switch ($role['platform']) { case SERVER_PLATFORMS::EC2: Modules_Platforms_Ec2_Helpers_Ebs::farmValidateRoleSettings($role['settings'], $dbRole->name); Modules_Platforms_Ec2_Helpers_Eip::farmValidateRoleSettings($role['settings'], $dbRole->name); Modules_Platforms_Ec2_Helpers_Elb::farmValidateRoleSettings($role['settings'], $dbRole->name); if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MYSQL)) { if ($role['settings'][DBFarmRole::SETTING_MYSQL_DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if ($dbRole->generation != 2) { if ($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == "" || $role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == "x-scalr-diff" || stristr($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE], 'x-scalr-custom')) { throw new Exception(sprintf(_("Requirement for EBS MySQL data storage is specific 'Placement' parameter for role '%s'"), $dbRole->name)); } } } } if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EPH) { if (!$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISK]) { throw new Exception(sprintf(_("Ephemeral disk settings is required for role '%s'"), $dbRole->name)); } } } if ($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == 'x-scalr-custom=') { throw new Exception(sprintf(_("Availability zone for role \"%s\" should be selected"), $dbRole->name)); } break; case SERVER_PLATFORMS::RDS: Modules_Platforms_Rds_Helpers_Rds::farmValidateRoleSettings($role['settings'], $dbRole->name); break; case SERVER_PLATFORMS::EUCALYPTUS: Modules_Platforms_Eucalyptus_Helpers_Eucalyptus::farmValidateRoleSettings($role['settings'], $dbRole->name); break; case SERVER_PLATFORMS::CLOUDSTACK: Modules_Platforms_Cloudstack_Helpers_Cloudstack::farmValidateRoleSettings($role['settings'], $dbRole->name); break; case SERVER_PLATFORMS::RACKSPACE: Modules_Platforms_Rackspace_Helpers_Rackspace::farmValidateRoleSettings($role['settings'], $dbRole->name); break; } Scalr_Helpers_Dns::farmValidateRoleSettings($role['settings'], $dbRole->name); } //Validate ClouFoundry stuff if (!empty($cloudFoundryStack)) { if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER]) { throw new Exception("CF CloudContoller role required for CloudFoundry stack. Please add All-in-one CF or separate CCHM role to farm"); } if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_HEALTH_MANAGER]) { throw new Exception("CF HealthManager role required for CloudFoundry stack. Please add All-in-one CF or separate CCHM role to farm"); } if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_ROUTER]) { throw new Exception("CF Router role required for CloudFoundry stack. Please add All-in-one CF or separate CF Router role to farm"); } if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_DEA]) { throw new Exception("CF DEA role required for CloudFoundry stack. Please add All-in-one CF or separate CF DEA role to farm"); } if (!$nginxFound) { throw new Exception("Nginx load balancer role required for CloudFoundry stack. Please add it to the farm"); } if ($cloudFoundryStack[ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER] > 1) { throw new Exception("CloudFoundry stack can work only with ONE CF CloudController role. Please leave only one CloudController role in farm"); } if ($cloudFoundryStack[ROLE_BEHAVIORS::CF_HEALTH_MANAGER] > 1) { throw new Exception("CloudFoundry stack can work only with ONE CF HealthManager role. Please leave only one HealthManager role in farm"); } if ($nginxFound > 1) { throw new Exception("CloudFoundry stack can work only with ONE nginx role. Please leave only one nginx role in farm"); } } $client = Client::Load($this->user->getAccountId()); if ($this->getParam('farmId')) { $dbFarm = DBFarm::LoadByID($this->getParam('farmId')); $this->user->getPermissions()->validate($dbFarm); } else { $this->user->getAccount()->validateLimit(Scalr_Limits::ACCOUNT_FARMS, 1); $dbFarm = new DBFarm(); $dbFarm->Status = FARM_STATUS::TERMINATED; } if ($this->getParam('farm')) { $farm = $this->getParam('farm'); $dbFarm->Name = strip_tags($farm['name']); $dbFarm->RolesLaunchOrder = $farm['roles_launch_order']; $dbFarm->Comments = trim(strip_tags($farm['description'])); } if (!$Validator->IsNotEmpty($dbFarm->Name)) { throw new Exception(_("Farm name required")); } $dbFarm->save(); if (!$dbFarm->GetSetting(DBFarm::SETTING_CRYPTO_KEY)) { $dbFarm->SetSetting(DBFarm::SETTING_CRYPTO_KEY, Scalr::GenerateRandomKey(40)); } $usedPlatforms = array(); $dbFarmRolesList = array(); $newFarmRolesList = array(); foreach ($this->getParam('roles') as $role) { if ($role['farm_role_id']) { $update = true; $dbFarmRole = DBFarmRole::LoadByID($role['farm_role_id']); $dbRole = DBRole::loadById($dbFarmRole->RoleID); $role['role_id'] = $dbFarmRole->RoleID; } else { $update = false; $dbRole = DBRole::loadById($role['role_id']); $dbFarmRole = $dbFarm->AddRole($dbRole, $role['platform'], $role['cloud_location'], (int) $role['launch_index']); } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES] = $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; } if ($dbFarmRole->NewRoleID) { continue; } if ($update) { $dbFarmRole->LaunchIndex = (int) $role['launch_index']; $dbFarmRole->Save(); } $usedPlatforms[$role['platform']] = 1; $oldRoleSettings = $dbFarmRole->GetAllSettings(); foreach ($role['scaling_settings'] as $k => $v) { $dbFarmRole->SetSetting($k, $v); } foreach ($role['settings'] as $k => $v) { $dbFarmRole->SetSetting($k, $v); } /****** Scaling settings ******/ $scalingManager = new Scalr_Scaling_Manager($dbFarmRole); $scalingManager->setFarmRoleMetrics($role['scaling']); //TODO: optimize this code... $this->db->Execute("DELETE FROM farm_role_scaling_times WHERE farm_roleid=?", array($dbFarmRole->ID)); // 5 = Time based scaling -> move to constants if ($role['scaling'][5]) { foreach ($role['scaling'][5] as $scal_period) { $chunks = explode(":", $scal_period['id']); $this->db->Execute("INSERT INTO farm_role_scaling_times SET\n\t\t\t\t\t\tfarm_roleid\t\t= ?,\n\t\t\t\t\t\tstart_time\t\t= ?,\n\t\t\t\t\t\tend_time\t\t= ?,\n\t\t\t\t\t\tdays_of_week\t= ?,\n\t\t\t\t\t\tinstances_count\t= ?\n\t\t\t\t\t", array($dbFarmRole->ID, $chunks[0], $chunks[1], $chunks[2], $chunks[3])); } } /*****************/ /* Update role params */ $dbFarmRole->SetParameters($role['params']); /* End of role params management */ /* Add script options to databse */ $dbFarmRole->SetScripts($role['scripting']); /* End of scripting section */ /* Add services configuration */ $dbFarmRole->SetServiceConfigPresets($role['config_presets']); /* End of scripting section */ Scalr_Helpers_Dns::farmUpdateRoleSettings($dbFarmRole, $oldRoleSettings, $role['settings']); foreach (Scalr_Role_Behavior::getListForFarmRole($dbFarmRole) as $behavior) { $behavior->onFarmSave($dbFarm, $dbFarmRole); } /** * Platfrom specified updates */ if ($dbFarmRole->Platform == SERVER_PLATFORMS::EC2) { Modules_Platforms_Ec2_Helpers_Ebs::farmUpdateRoleSettings($dbFarmRole, $oldRoleSettings, $role['settings']); Modules_Platforms_Ec2_Helpers_Eip::farmUpdateRoleSettings($dbFarmRole, $oldRoleSettings, $role['settings']); Modules_Platforms_Ec2_Helpers_Elb::farmUpdateRoleSettings($dbFarmRole, $oldRoleSettings, $role['settings']); } $dbFarmRolesList[] = $dbFarmRole; $newFarmRolesList[] = $dbFarmRole->ID; } if (!$this->getParam('roleUpdate')) { foreach ($dbFarm->GetFarmRoles() as $dbFarmRole) { if (!$dbFarmRole->NewRoleID && !in_array($dbFarmRole->ID, $newFarmRolesList)) { $dbFarmRole->Delete(); } } } if ($usedPlatforms[SERVER_PLATFORMS::CLOUDSTACK]) { Modules_Platforms_Cloudstack_Helpers_Cloudstack::farmSave($dbFarm, $dbFarmRolesList); } if ($usedPlatforms[SERVER_PLATFORMS::EC2]) { Modules_Platforms_Ec2_Helpers_Ec2::farmSave($dbFarm, $dbFarmRolesList); } if ($usedPlatforms[SERVER_PLATFORMS::EUCALYPTUS]) { Modules_Platforms_Eucalyptus_Helpers_Eucalyptus::farmSave($dbFarm, $dbFarmRolesList); } $dbFarm->save(); if (!$client->GetSettingValue(CLIENT_SETTINGS::DATE_FARM_CREATED)) { $client->SetSettingValue(CLIENT_SETTINGS::DATE_FARM_CREATED, time()); } $this->response->success('Farm successfully saved'); $this->response->data(array('farmId' => $dbFarm->ID)); }
/** * * @param array $farmSettings * @param array $roles * @return bool */ private function isFarmConfigurationValid($farmId, $farmSettings, array $roles = array()) { $this->errors = array('error_count' => 0); $farmVariables = new Scalr_Scripting_GlobalVariables($this->getEnvironmentId(), Scalr_Scripting_GlobalVariables::SCOPE_FARM); $farmRoleVariables = new Scalr_Scripting_GlobalVariables($this->getEnvironmentId(), Scalr_Scripting_GlobalVariables::SCOPE_FARMROLE); if ($farmSettings['variables']) { $result = $farmVariables->validateValues($farmSettings['variables'], 0, $farmId); if ($result !== TRUE) { $this->setBuildError('variables', $result); } } if (!empty($roles)) { $cloudFoundryStack = array(); $hasVpcRouter = false; $nginxFound = 0; foreach ($roles as $role) { $dbRole = DBRole::loadById($role['role_id']); if (!$dbRole->getImageId($role['platform'], $role['cloud_location'])) { $this->setBuildError($dbRole->name, sprintf(_("Role '%s' is not available in %s on %s"), $dbRole->name, $role['platform'], $role['cloud_location']), $role['farm_role_id']); } if ($role['alias']) { if (!preg_match("/^[A-Za-z0-9]+[A-Za-z0-9-]*[A-Za-z0-9]+\$/si", $role['alias'])) { $this->setBuildError('alias', sprintf(_("Alias for role '%s' should start and end with letter or number and contain only letters, numbers and dashes."), $dbRole->name, $role['platform'], $role['cloud_location']), $role['farm_role_id']); } } // Validate deployments $appId = $role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID]; if ($appId) { $application = Scalr_Dm_Application::init()->loadById($appId); $this->user->getPermissions()->validate($application); if (!$role[Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH]) { $this->setBuildError(Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH, sprintf("Remote path required for deployment on role '%s'", $dbRole->name), $role['farm_role_id']); } } //-- CloudFoundryStuff if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_DEA)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_DEA] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_HEALTH_MANAGER)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_HEALTH_MANAGER] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_ROUTER)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_ROUTER] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CF_SERVICE)) { $cloudFoundryStack[ROLE_BEHAVIORS::CF_SERVICE] = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { $hasVpcRouter = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::NGINX)) { $nginxFound++; } //-- End CloudFoundry stuff if ($dbRole->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES] = $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] = (int) $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO]; if ($role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] < 1 || $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] > 100) { $this->setBuildError(Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO, sprintf("Nodes ratio for RabbitMq role '%s' should be between 1 and 100", $dbRole->name), $role['farm_role_id']); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE] == 'ebs') { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] < 10 || $role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] > 1000) { $this->setBuildError(Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE, sprintf("EBS size for mongoDB role should be between 10 and 1000 GB", $dbRole->name), $role['farm_role_id']); } } } /* Validate scaling */ $minCount = (int) $role['settings'][DBFarmRole::SETTING_SCALING_MIN_INSTANCES]; if (!$minCount && $minCount != 0) { $minCount = 1; } if ($minCount < 0 || $minCount > 400) { $this->setBuildError(DBFarmRole::SETTING_SCALING_MIN_INSTANCES, sprintf(_("Min instances for '%s' must be a number between 1 and 400"), $dbRole->name), $role['farm_role_id']); } $maxCount = (int) $role['settings'][DBFarmRole::SETTING_SCALING_MAX_INSTANCES]; if (!$maxCount) { $maxCount = 1; } if ($maxCount < 1 || $maxCount > 400) { $this->setBuildError(DBFarmRole::SETTING_SCALING_MAX_INSTANCES, sprintf(_("Max instances for '%s' must be a number between 1 and 400"), $dbRole->name), $role['farm_role_id']); } if ($maxCount < $minCount) { $this->setBuildError(DBFarmRole::SETTING_SCALING_MAX_INSTANCES, sprintf(_("Max instances should be greater or equal than Min instances for role '%s'"), $dbRole->name), $role['farm_role_id']); } if (isset($role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL]) && $role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL] > 0) { $polling_interval = (int) $role['settings'][DBFarmRole::SETTING_SCALING_POLLING_INTERVAL]; } else { $polling_interval = 2; } if ($polling_interval < 1 || $polling_interval > 50) { $this->setBuildError(DBFarmRole::SETTING_SCALING_POLLING_INTERVAL, sprintf(_("Polling interval for role '%s' must be a number between 1 and 50"), $dbRole->name), $role['farm_role_id']); } /** Validate platform specified settings **/ switch ($role['platform']) { case SERVER_PLATFORMS::EC2: if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MYSQL)) { if ($role['settings'][DBFarmRole::SETTING_MYSQL_DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if ($dbRole->generation != 2) { if ($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == "" || $role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == "x-scalr-diff" || stristr($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE], 'x-scalr-custom')) { $this->setBuildError(DBFarmRole::SETTING_AWS_AVAIL_ZONE, sprintf(_("Requirement for EBS MySQL data storage is specific 'Placement' parameter for role '%s'"), $dbRole->name), $role['farm_role_id']); } } } } if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EPH) { if (!$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISK] && !$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISKS]) { $this->setBuildError(Scalr_Db_Msr::DATA_STORAGE_EPH_DISK, sprintf(_("Ephemeral disk settings is required for role '%s'"), $dbRole->name), $role['farm_role_id']); } } if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::LVM) { if (!$role['settings'][Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES]) { $this->setBuildError(Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES, sprintf(_("Ephemeral disks settings is required for role '%s'"), $dbRole->name), $role['farm_role_id']); } } if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::RAID_EBS) { if (!$this->user->getAccount()->isFeatureEnabled(Scalr_Limits::FEATURE_RAID)) { $this->setBuildError(Scalr_Db_Msr::DATA_STORAGE_ENGINE, 'RAID arrays are not available for your pricing plan. <a href="#/billing">Please upgrade your account to be able to use this feature.</a>', $role['farm_role_id']); } } if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_FSTYPE] && $role['settings'][Scalr_Db_Msr::DATA_STORAGE_FSTYPE] != 'ext3') { if (!$this->user->getAccount()->isFeatureEnabled(Scalr_Limits::FEATURE_MFS)) { $this->setBuildError(Scalr_Db_Msr::DATA_STORAGE_ENGINE, 'Only ext3 filesystem available for your pricing plan. <a href="#/billing">Please upgrade your account to be able to use other filesystems.</a>', $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::RAID_EBS) { if (!$this->user->getAccount()->isFeatureEnabled(Scalr_Limits::FEATURE_RAID)) { $this->setBuildError(Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE, 'RAID arrays are not available for your pricing plan. <a href="#/billing">Please upgrade your account to be able to use this feature.</a>', $role['farm_role_id']); } } } if ($role['settings'][DBFarmRole::SETTING_AWS_AVAIL_ZONE] == 'x-scalr-custom=') { $this->setBuildError(DBFarmRole::SETTING_AWS_AVAIL_ZONE, sprintf(_("Availability zone for role \"%s\" should be selected"), $dbRole->name), $role['farm_role_id']); } break; case SERVER_PLATFORMS::CLOUDSTACK: if (!$role['settings'][DBFarmRole::SETTING_CLOUDSTACK_SERVICE_OFFERING_ID]) { $this->setBuildError(DBFarmRole::SETTING_CLOUDSTACK_SERVICE_OFFERING_ID, sprintf(_("Service offering for '%s' cloudstack role should be selected on 'Cloudstack settings' tab"), $dbRole->name), $role['farm_role_id']); } break; case SERVER_PLATFORMS::RACKSPACE: if (!$role['settings'][DBFarmRole::SETTING_RS_FLAVOR_ID]) { $this->setBuildError(DBFarmRole::SETTING_CLOUDSTACK_SERVICE_OFFERING_ID, sprintf(_("Flavor for '%s' rackspace role should be selected on 'Placement and type' tab"), $dbRole->name), $role['farm_role_id']); } break; } if ($role['settings'][DBFarmRole::SETTING_DNS_CREATE_RECORDS]) { if ($role['settings'][DBFarmRole::SETTING_DNS_EXT_RECORD_ALIAS]) { if (!preg_match("/^[A-Za-z0-9-%_]+\$/si", $role['settings'][DBFarmRole::SETTING_DNS_EXT_RECORD_ALIAS])) { $this->setBuildError(DBFarmRole::SETTING_DNS_EXT_RECORD_ALIAS, "ext-%rolename% record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not by hypen.", $role['farm_role_id']); } } if ($role['settings'][DBFarmRole::SETTING_DNS_INT_RECORD_ALIAS]) { if (!preg_match("/^[A-Za-z0-9-%_]+\$/si", $role['settings'][DBFarmRole::SETTING_DNS_INT_RECORD_ALIAS])) { $this->setBuildError(DBFarmRole::SETTING_DNS_INT_RECORD_ALIAS, "int-%rolename% record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not by hypen.", $role['farm_role_id']); } } } //DEPRECATED $rParams = $dbRole->getParameters(); if (count($rParams) > 0 && strpos($role['farm_role_id'], 'virtual_') === false) { if (empty($role['params'])) { try { $dbFarmRole = DBFarmRole::LoadByID($role['farm_role_id']); foreach ($rParams as $param) { $farmRoleOption = $this->db->GetRow("SELECT id, value FROM farm_role_options WHERE farm_roleid=? AND `hash`=? LIMIT 1", array($dbFarmRole->ID, $param['hash'])); if ($farmRoleOption['id']) { $value = $farmRoleOption['value']; } $role['params'][$param['hash']] = $value; } } catch (Exception $e) { } } } //Validate role parameters foreach ($rParams as $p) { if ($p['required'] && $role['params'][$p['hash']] == "" && !$p['defval']) { $this->setBuildError($p['name'], "Missed required parameter '{$p['name']}' for role '{$dbRole->name}'", $role['farm_role_id']); } } // Validate Global variables if (!strstr($role['farm_role_id'], 'virtual_')) { $farmRole = DBFarmRole::LoadByID($role['farm_role_id']); } else { $farmRole = null; } $result = $farmRoleVariables->validateValues($role['variables'], $dbRole->id, $farmId, $farmRole ? $farmRole->ID : 0); if ($result !== TRUE) { $this->setBuildError('variables', $result, $role['farm_role_id']); } } } try { if (!empty($cloudFoundryStack)) { if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER]) { throw new Exception("CF CloudContoller role required for CloudFoundry stack. Please add All-in-one CF or separate CCHM role to farm"); } if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_HEALTH_MANAGER]) { throw new Exception("CF HealthManager role required for CloudFoundry stack. Please add All-in-one CF or separate CCHM role to farm"); } if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_ROUTER]) { throw new Exception("CF Router role required for CloudFoundry stack. Please add All-in-one CF or separate CF Router role to farm"); } if (!$cloudFoundryStack[ROLE_BEHAVIORS::CF_DEA]) { throw new Exception("CF DEA role required for CloudFoundry stack. Please add All-in-one CF or separate CF DEA role to farm"); } if (!$nginxFound) { throw new Exception("Nginx load balancer role required for CloudFoundry stack. Please add it to the farm"); } if ($cloudFoundryStack[ROLE_BEHAVIORS::CF_CLOUD_CONTROLLER] > 1) { throw new Exception("CloudFoundry stack can work only with ONE CF CloudController role. Please leave only one CloudController role in farm"); } if ($cloudFoundryStack[ROLE_BEHAVIORS::CF_HEALTH_MANAGER] > 1) { throw new Exception("CloudFoundry stack can work only with ONE CF HealthManager role. Please leave only one HealthManager role in farm"); } if ($nginxFound > 1) { throw new Exception("CloudFoundry stack can work only with ONE nginx role. Please leave only one nginx role in farm"); } } } catch (Exception $e) { $this->setBuildError('general', $e->getMessage(), null); } if ($farmSettings['vpc_id']) { $vpcRouterRequired = false; if (\Scalr::config('scalr.instances_connection_policy') != 'local' && !$hasVpcRouter) { foreach ($this->getParam('roles') as $role) { if ($role['settings'][DBFarmRole::SETTING_AWS_VPC_INTERNET_ACCESS] == 'outbound-only') { $vpcRouterRequired = true; break; } } if ($vpcRouterRequired) { $this->setBuildError('general', "VPC Router role required for farm that running inside VPC with roles configured for outbound-only internet access", null); } } } return $this->errors['error_count'] == 0 ? true : false; }
/** * * @param array $farmSettings * @param array $roles * @return bool */ private function isFarmConfigurationValid($farmId, $farmSettings, array $roles = array()) { $this->errors = array('error_count' => 0); $farmVariables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), ScopeInterface::SCOPE_FARM); $farmRoleVariables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), ScopeInterface::SCOPE_FARMROLE); $name = $this->request->stripValue($farmSettings['name']); if (empty($name)) { $this->setBuildError('name', 'Farm name is invalid'); } if ($farmSettings['variables']) { $result = $farmVariables->validateValues(is_array($farmSettings['variables']) ? $farmSettings['variables'] : [], 0, $farmId); if ($result !== TRUE) { $this->setBuildError('variables', $result); } } if (is_numeric($farmSettings['owner'])) { try { $u = (new Scalr_Account_User())->loadById($farmSettings['owner']); if ($u->getAccountId() != $this->user->getAccountId()) { throw new Exception('User not found'); } } catch (Exception $e) { $this->setBuildError('owner', $e->getMessage()); } } if (is_numeric($farmSettings['teamOwner']) && $farmSettings['teamOwner'] > 0) { if ($this->user->canManageAcl()) { $teams = $this->db->getAll('SELECT id, name FROM account_teams WHERE account_id = ?', array($this->user->getAccountId())); } else { $teams = $this->user->getTeams(); } if (!in_array($farmSettings['teamOwner'], array_map(function ($t) { return $t['id']; }, $teams))) { if ($this->db->GetOne('SELECT team_id FROM farms WHERE id = ?', [$farmId]) != $farmSettings['teamOwner']) { $this->setBuildError('teamOwner', 'Team not found'); } } } if (!empty($roles)) { $hasVpcRouter = false; $vpcRouterRequired = false; $governance = new Scalr_Governance($this->getEnvironmentId()); foreach ($roles as $role) { $dbRole = DBRole::loadById($role['role_id']); if (!$this->hasPermissions($dbRole->__getNewRoleObject())) { $this->setBuildError($dbRole->name, 'You don\'t have access to this role'); } try { $dbRole->__getNewRoleObject()->getImage($role['platform'], $role['cloud_location']); } catch (Exception $e) { $this->setBuildError($dbRole->name, sprintf("Role '%s' is not available in %s on %s", $dbRole->name, $role['platform'], $role['cloud_location'])); } if ($role['alias']) { if (!preg_match("/^[[:alnum:]](?:-*[[:alnum:]])*\$/", $role['alias'])) { $this->setBuildError('alias', 'Alias should start and end with letter or number and contain only letters, numbers and dashes.', $role['farm_role_id']); } } // Validate deployments if (isset($role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID])) { $application = Scalr_Dm_Application::init()->loadById($role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID]); $this->user->getPermissions()->validate($application); if (!$role[Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH]) { $this->setBuildError(Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH, 'Remote path is required for deployment', $role['farm_role_id']); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { $hasVpcRouter = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $role['settings'][Entity\FarmRoleSetting::SCALING_MAX_INSTANCES] = $role['settings'][Entity\FarmRoleSetting::SCALING_MIN_INSTANCES]; $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] = (int) $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO]; if ($role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] < 1 || $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] > 100) { $this->setBuildError(Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO, 'Nodes ratio should be an integer between 1 and 100', $role['farm_role_id']); } else { $this->checkInteger($role['farm_role_id'], Scalr_Role_Behavior_RabbitMQ::ROLE_DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_DATA_STORAGE_EBS_SIZE], 'Storage size', 1, 1000); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE] == 'ebs') { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] < 10 || $role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] > 1000) { $this->setBuildError(Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE, sprintf("EBS size for mongoDB role should be between 10 and 1000 GB", $dbRole->name), $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::NGINX)) { $proxies = (array) @json_decode($role['settings'][Scalr_Role_Behavior_Nginx::ROLE_PROXIES], true); foreach ($proxies as $proxyIndex => $proxy) { if ($proxy['ssl'] == 1) { if (empty($proxy['ssl_certificate_id'])) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'SSL certificate is required', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); break; } if ($proxy['port'] == $proxy['ssl_port']) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'HTTP and HTTPS ports cannot be the same', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); } } if (count($proxy['backends']) > 0) { foreach ($proxy['backends'] as $backend) { if (empty($backend['farm_role_id']) && empty($backend['farm_role_alias']) && empty($backend['host'])) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'Destination is required', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); break; } } } } } /* Validate scaling */ if (!$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER) && !$dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { $minCount = $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_MIN_INSTANCES, $role['settings'][Entity\FarmRoleSetting::SCALING_MIN_INSTANCES], 'Min instances', 0, 400); $maxCount = $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_MAX_INSTANCES, $role['settings'][Entity\FarmRoleSetting::SCALING_MAX_INSTANCES], 'Max instances', 1, 400); if ($minCount !== false && $maxCount !== false && $maxCount < $minCount) { $this->setBuildError(Entity\FarmRoleSetting::SCALING_MAX_INSTANCES, 'Max instances should be greater than or equal to Min instances', $role['farm_role_id']); } $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_POLLING_INTERVAL, $role['settings'][Entity\FarmRoleSetting::SCALING_POLLING_INTERVAL], 'Polling interval', 1, 50); if (array_key_exists(Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT_ENABLED, $role["settings"]) && $role['settings'][Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT], 'Upscale timeout', 1); } if (array_key_exists(Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT_ENABLED, $role["settings"]) && $role['settings'][Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT], 'Downscale timeout', 1); } if (is_array($role['scaling'])) { foreach ($role['scaling'] as $metricId => $metricSettings) { $hasError = false; if ($metricId == Entity\ScalingMetric::METRIC_URL_RESPONSE_TIME_ID) { $hasError = Validator::validateUrl($metricSettings['url']) !== true || Validator::validateInteger($metricSettings['min']) !== true || Validator::validateInteger($metricSettings['max']) !== true; } elseif ($metricId == Entity\ScalingMetric::METRIC_SQS_QUEUE_SIZE_ID) { $hasError = Validator::validateNotEmpty($metricSettings['queue_name']) !== true || Validator::validateInteger($metricSettings['min']) !== true || Validator::validateInteger($metricSettings['max']) !== true; } elseif (in_array($metricId, [Entity\ScalingMetric::METRIC_LOAD_AVERAGES_ID, Entity\ScalingMetric::METRIC_FREE_RAM_ID, Entity\ScalingMetric::METRIC_BANDWIDTH_ID])) { $hasError = Validator::validateFloat($metricSettings['min']) !== true || Validator::validateFloat($metricSettings['max']) !== true; } if ($hasError) { $this->setBuildError('scaling', ['message' => 'Scaling metric settings are invalid', 'invalidIndex' => $metricId], $role['farm_role_id']); break; } } } } /* Validate advanced settings */ if (!$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { if (isset($role['settings'][Scalr_Role_Behavior::ROLE_BASE_API_PORT])) { $this->checkInteger($role['farm_role_id'], Scalr_Role_Behavior::ROLE_BASE_API_PORT, $role['settings'][Scalr_Role_Behavior::ROLE_BASE_API_PORT], 'Scalarizr API port', 1, 65535); } if (isset($role['settings'][Scalr_Role_Behavior::ROLE_BASE_MESSAGING_PORT])) { $this->checkInteger($role['farm_role_id'], Scalr_Role_Behavior::ROLE_BASE_MESSAGING_PORT, $role['settings'][Scalr_Role_Behavior::ROLE_BASE_MESSAGING_PORT], 'Scalarizr control port', 1, 65535); } if (isset($role['settings'][Entity\FarmRoleSetting::SYSTEM_REBOOT_TIMEOUT])) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SYSTEM_REBOOT_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SYSTEM_REBOOT_TIMEOUT], 'Reboot timeout', 1); } if (isset($role['settings'][Entity\FarmRoleSetting::SYSTEM_LAUNCH_TIMEOUT])) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SYSTEM_LAUNCH_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SYSTEM_LAUNCH_TIMEOUT], 'Launch timeout', 1); } } /* Validate chef settings */ if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CHEF)) { if ($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_BOOTSTRAP] == 1) { if (empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL]) && empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID])) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID, 'Chef Server or Chef Solo must be setup if using Chef to bootstrap Role', $role['farm_role_id']); } elseif ($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL_TYPE] == 'http' && !empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL]) && Validator::validateUrl($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL]) !== true) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL, 'Cookbook URL is invalid.', $role['farm_role_id']); } } elseif ($dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_BOOTSTRAP) == 1 && $dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID)) { if (strpos($role['farm_role_id'], "virtual_") !== false) { $chefGovernance = $governance->getValue(Scalr_Governance::CATEGORY_GENERAL, Scalr_Governance::GENERAL_CHEF, 'servers'); if ($chefGovernance !== null && !isset($chefGovernance[$dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID)])) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID, 'Chef server is not allowed by Governance.', $role['farm_role_id']); } } if (empty($dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT)) && empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT])) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT, 'Chef Environment is required', $role['farm_role_id']); } } } /** Validate platform specified settings **/ switch ($role['platform']) { case SERVER_PLATFORMS::EC2: if (!empty($role['settings'][Entity\FarmRoleSetting::AWS_TAGS_LIST])) { $reservedBaseCustomTags = ['scalr-meta', 'Name']; $baseCustomTags = @explode("\n", $role['settings'][Entity\FarmRoleSetting::AWS_TAGS_LIST]); foreach ((array) $baseCustomTags as $tag) { $tag = trim($tag); $tagChunks = explode("=", $tag); if (in_array(trim($tagChunks[0]), $reservedBaseCustomTags)) { $this->setBuildError(Entity\FarmRoleSetting::AWS_TAGS_LIST, "Avoid using Scalr-reserved tag names.", $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MYSQL)) { if ($role['settings'][Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if ($dbRole->generation != 2 && isset($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE])) { if ($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE] == "" || $role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE] == "x-scalr-diff" || stristr($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE], 'x-scalr-custom')) { $this->setBuildError(Entity\FarmRoleSetting::AWS_AVAIL_ZONE, 'Requirement for EBS MySQL data storage is specific \'Placement\' parameter', $role['farm_role_id']); } } } } if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EPH) { if (!$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISK] && !$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISKS]) { $this->setBuildError(Scalr_Db_Msr::DATA_STORAGE_EPH_DISK, 'Ephemeral disk settings is required', $role['farm_role_id']); } } elseif ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if (array_key_exists(Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE, $role["settings"])) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE] == CreateVolumeRequestData::VOLUME_TYPE_STANDARD) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE], 'Storage size', 1, 1024); } elseif ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE] == CreateVolumeRequestData::VOLUME_TYPE_GP2) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE], 'Storage size', 1, 16384); } elseif ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE] == CreateVolumeRequestData::VOLUME_TYPE_IO1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE], 'Storage size', 4, 16384); $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_IOPS, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_IOPS], 'IOPS', 100, 20000); } } } if (array_key_exists(Scalr_Db_Msr::DATA_STORAGE_EBS_ENABLE_ROTATION, $role["settings"]) && $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_ENABLE_ROTATION] == 1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_ROTATE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_ROTATE], 'Snapshot rotation limit', 1); } if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::LVM) { if (!$role['settings'][Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES]) { $this->setBuildError(Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES, 'LVM storage settings is required', $role['farm_role_id']); } } } if ($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE] == 'x-scalr-custom=') { $this->setBuildError(Entity\FarmRoleSetting::AWS_AVAIL_ZONE, 'Availability zone should be selected', $role['farm_role_id']); } if (!empty($farmSettings['vpc_id'])) { $sgs = @json_decode($role['settings'][Entity\FarmRoleSetting::AWS_SECURITY_GROUPS_LIST]); if (!$governance->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_SECURITY_GROUPS) && !$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER) && empty($sgs) && empty($role['settings'][Entity\FarmRoleSetting::AWS_SG_LIST])) { $this->setBuildError(Entity\FarmRoleSetting::AWS_SECURITY_GROUPS_LIST, 'Security group(s) should be selected', $role['farm_role_id']); } $subnets = @json_decode($role['settings'][Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID]); if (empty($subnets)) { $this->setBuildError(Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID, 'VPC Subnet(s) should be selected', $role['farm_role_id']); } if (\Scalr::config('scalr.instances_connection_policy') != 'local' && empty($role['settings'][Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID])) { try { if (!empty($subnets[0])) { $platform = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); $info = $platform->listSubnets($this->getEnvironment(), $role['cloud_location'], $farmSettings['vpc_id'], true, $subnets[0]); if (!empty($info["type"]) && $info['type'] == 'private') { $vpcRouterRequired = $role['farm_role_id']; } } } catch (Exception $e) { } } } break; case SERVER_PLATFORMS::CLOUDSTACK: if (!$role['settings'][Entity\FarmRoleSetting::CLOUDSTACK_SERVICE_OFFERING_ID]) { $this->setBuildError(Entity\FarmRoleSetting::CLOUDSTACK_SERVICE_OFFERING_ID, 'Service offering should be selected', $role['farm_role_id']); } break; case SERVER_PLATFORMS::RACKSPACE: if (!$role['settings'][Entity\FarmRoleSetting::RS_FLAVOR_ID]) { $this->setBuildError(Entity\FarmRoleSetting::CLOUDSTACK_SERVICE_OFFERING_ID, 'Flavor should be selected', $role['farm_role_id']); } break; case SERVER_PLATFORMS::GCE: if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::GCE_PERSISTENT) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_GCED_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_GCED_SIZE], 'Storage size', 1); } } break; } if ($dbRole->getDbMsrBehavior()) { if (array_key_exists(Scalr_Db_Msr::DATA_BUNDLE_ENABLED, $role["settings"]) && $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_EVERY, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_EVERY], 'Bundle period', 1); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_HH, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_HH], 'Preferred bundle window start HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_MM, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_MM], 'Preferred bundle window start MM is invalid', '/^[0-5][0-9]$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_HH, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_HH], 'Preferred bundle window end HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_MM, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_MM], 'Preferred bundle window end MM is invalid', '/^[0-5][0-9]$/'); } if (array_key_exists(Scalr_Db_Msr::DATA_BACKUP_ENABLED, $role["settings"]) && $role['settings'][Scalr_Db_Msr::DATA_BACKUP_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_EVERY, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_EVERY], 'Backup period', 1); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_HH, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_HH], 'Preferred backup window start HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_MM, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_MM], 'Preferred backup window start MM is invalid', '/^[0-5][0-9]$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_HH, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_HH], 'Preferred backup window end HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_MM, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_MM], 'Preferred backup window end MM is invalid', '/^[0-5][0-9]$/'); } } if (!empty($role['settings'][Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS]) && PlatformFactory::isOpenstack($role['platform'])) { $reservedBaseCustomTags = ['scalr-meta', 'farmid', 'role', 'httpproto', 'region', 'hash', 'realrolename', 'szr_key', 'serverid', 'p2p_producer_endpoint', 'queryenv_url', 'behaviors', 'farm_roleid', 'roleid', 'env_id', 'platform', 'server_index', 'cloud_server_id', 'cloud_location_zone', 'owner_email']; $baseCustomTags = @explode("\n", $role['settings'][Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS]); foreach ((array) $baseCustomTags as $tag) { $tag = trim($tag); $tagChunks = explode("=", $tag); if (in_array(trim($tagChunks[0]), $reservedBaseCustomTags)) { $this->setBuildError(Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS, "Avoid using Scalr-reserved metadata names.", $role['farm_role_id']); } } } if (!empty($role['settings'][Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT])) { if (!preg_match('/^[\\w\\{\\}\\.-]+$/', $role['settings'][Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT])) { $this->setBuildError(Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT, "server hostname format for role'{$dbRole->name}' should contain only [a-z0-9-] chars. First char should not be hypen.", $role['farm_role_id']); } } if (!empty($role['settings'][Entity\FarmRoleSetting::DNS_CREATE_RECORDS])) { if ($role['settings'][Entity\FarmRoleSetting::DNS_EXT_RECORD_ALIAS]) { if (!preg_match('/^[\\w\\{\\}\\.-]+$/', $role['settings'][Entity\FarmRoleSetting::DNS_EXT_RECORD_ALIAS])) { $this->setBuildError(Entity\FarmRoleSetting::DNS_EXT_RECORD_ALIAS, "ext- record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not be hypen.", $role['farm_role_id']); } } if ($role['settings'][Entity\FarmRoleSetting::DNS_INT_RECORD_ALIAS]) { if (!preg_match('/^[\\w\\{\\}\\.-]+$/', $role['settings'][Entity\FarmRoleSetting::DNS_INT_RECORD_ALIAS])) { $this->setBuildError(Entity\FarmRoleSetting::DNS_INT_RECORD_ALIAS, "int- record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not by hypen.", $role['farm_role_id']); } } } // Validate Global variables if (!strstr($role['farm_role_id'], 'virtual_')) { $farmRole = DBFarmRole::LoadByID($role['farm_role_id']); } else { $farmRole = null; if ($dbRole->isDeprecated == 1) { $this->setBuildError('roleId', 'This role has been deprecated and cannot be added', $role['farm_role_id']); } if (!empty($envs = $dbRole->__getNewRoleObject()->getAllowedEnvironments())) { if (!in_array($this->getEnvironmentId(), $envs)) { $this->setBuildError('roleId', "You don't have access to this role", $role['farm_role_id']); } } } if (isset($role['storages']['configs'])) { // TODO: refactor, get rid of using DBFarmRole in constructor $fr = $farmRole ? $farmRole : new DBFarmRole(0); foreach ($fr->getStorage()->validateConfigs($role['storages']['configs']) as $index => $message) { $this->setBuildError('storages', ['message' => $message, 'invalidIndex' => $index], $role['farm_role_id']); break; } } $result = $farmRoleVariables->validateValues(is_array($role['variables']) ? $role['variables'] : [], $dbRole->id, $farmId, $farmRole ? $farmRole->ID : 0); if ($result !== TRUE) { $this->setBuildError('variables', $result, $role['farm_role_id']); } } } if ($farmSettings['vpc_id']) { if (!$hasVpcRouter && $vpcRouterRequired) { $this->setBuildError(Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID, 'You must select a VPC Router for Farm Roles launched in a Private VPC Subnet', $vpcRouterRequired); } } if ($this->getContainer()->analytics->enabled) { if ($farmSettings['projectId']) { $project = $this->getContainer()->analytics->projects->get($farmSettings['projectId']); if (!$project) { $this->setBuildError('projectId', 'Project not found', null); } else { if ($project->ccId != $this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)) { $this->setBuildError('projectId', 'Invalid project identifier. Project should correspond to the Environment\'s cost center.', null); } } } else { $this->setBuildError('projectId', 'Project field is required', null); } } return $this->errors['error_count'] == 0 ? true : false; }
public function extendMessage(Scalr_Messaging_Msg $message, DBServer $dbServer) { switch (get_class($message)) { case "Scalr_Messaging_Msg_HostInitResponse": try { if ($dbServer->farmRoleId) { $appId = $dbServer->GetFarmRoleObject()->GetSetting(self::ROLE_DM_APPLICATION_ID); if (!$message->deploy && $appId) { $application = Scalr_Dm_Application::init()->loadById($appId); $deploymentTask = Scalr_Dm_DeploymentTask::init(); $deploymentTask->create($dbServer->farmRoleId, $appId, $dbServer->serverId, Scalr_Dm_DeploymentTask::TYPE_AUTO, $dbServer->GetFarmRoleObject()->GetSetting(self::ROLE_DM_REMOTE_PATH), $dbServer->envId, Scalr_Dm_DeploymentTask::STATUS_DEPLOYING); $msg = $deploymentTask->getDeployMessage(); $message->deploy = $msg; } } } catch (Exception $e) { $this->logger->error(new FarmLogMessage($dbServer->farmId, "Cannot init deployment: {$e->getMessage()}")); } break; } return $message; }