/** * @deprecated Use method FarmRole::getImage * * @return Image|NULL * @throws \Exception */ public function getImage() { /* @var $role Role */ $role = Role::findPk($this->roleId); $criteria = [['id' => $this->imageId], ['platform' => $this->platform], ['cloudLocation' => $this->cloudLocation], ['$or' => [['accountId' => null], ['$and' => [['accountId' => $role->accountId], ['$or' => [['envId' => null], ['envId' => $role->envId]]]]]]]]; return Image::findOne($criteria); }
/** * Checks whether Image does exist in the user's scope * * @param string $cloudImageId The identifier of the image on the Cloud * @param string $platform The cloud platform * @param string $cloudLocation The cloud location * @return bool Returns TRUE if image exists in the user's scope * @throws ApiErrorException */ public function getImageByCloudId($cloudImageId, $platform, $cloudLocation) { $criteria = array_merge($this->getDefaultCriteria(), [['id' => $cloudImageId], ['platform' => $platform], ['cloudLocation' => $cloudLocation]]); $image = Entity\Image::findOne($criteria); if (!$image) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Image either does not exist or is not owned by your environment."); } return $image; }
protected function run1($stage) { $this->db->Execute("CREATE TABLE `image_software` (\n `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n `image_hash` binary(16) NOT NULL DEFAULT '',\n `name` varchar(45) NOT NULL DEFAULT '',\n `version` varchar(20) DEFAULT NULL,\n PRIMARY KEY (`id`),\n KEY `idx_image_hash` (`image_hash`)\n ) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n "); $this->db->Execute('ALTER TABLE image_software ADD CONSTRAINT `fk_images_hash_image_software` FOREIGN KEY (`image_hash`) REFERENCES `images` (`hash`) ON DELETE CASCADE ON UPDATE NO ACTION'); foreach ($this->db->GetAll('SELECT role_images.*, roles.env_id FROM role_images LEFT JOIN roles ON roles.id = role_images.role_id') as $image) { $props = []; foreach ($this->db->GetAll('SELECT * FROM role_software WHERE role_id = ?', [$image['role_id']]) as $soft) { if ($soft['software_name']) { $name = explode(' ', trim($soft['software_name'], '*- ')); $version = $soft['software_version']; if (count($name) > 1) { $version = $name[1]; $name = strtolower($name[0]); } else { $name = strtolower($name[0]); } if (preg_match('/^[a-z]+$/', $name)) { $props[$name] = $version; } } } if (empty($props)) { // check role behaviours $beh = $this->db->GetCol('SELECT behavior FROM role_behaviors WHERE role_id = ?', [$image['role_id']]); foreach ($beh as $b) { if (in_array($b, [\ROLE_BEHAVIORS::MYSQL, \ROLE_BEHAVIORS::PERCONA, \ROLE_BEHAVIORS::TOMCAT, \ROLE_BEHAVIORS::MEMCACHED, \ROLE_BEHAVIORS::POSTGRESQL, \ROLE_BEHAVIORS::REDIS, \ROLE_BEHAVIORS::RABBITMQ, \ROLE_BEHAVIORS::MONGODB, \ROLE_BEHAVIORS::CHEF, \ROLE_BEHAVIORS::MYSQLPROXY, \ROLE_BEHAVIORS::HAPROXY, \ROLE_BEHAVIORS::MARIADB])) { $props[$b] = null; } else { if ($b == \ROLE_BEHAVIORS::MYSQL2) { $props['mysql'] = null; } else { if ($b == \ROLE_BEHAVIORS::NGINX) { $props['nginx'] = null; } else { if ($b == \ROLE_BEHAVIORS::APACHE) { $props['apache'] = null; } } } } } } $obj = Image::findOne([['id' => $image['image_id']], ['envId' => $image['env_id'] == 0 ? NULL : $image['env_id']], ['platform' => $image['platform']], ['cloudLocation' => $image['cloud_location']]]); /* @var Image $obj */ if ($obj) { $obj->setSoftware($props); } else { if (!Image::findOne([['id' => $image['image_id']], ['envId' => NULL], ['platform' => $image['platform']], ['cloudLocation' => $image['cloud_location']]])) { $this->console->warning('Image not found: %s', $image['image_id']); } } } $this->db->Execute('RENAME TABLE role_software TO role_software_deleted'); }
public function xAttachAction() { $aws = $this->getEnvironment()->aws($this->getParam('cloudLocation')); $this->request->defineParams(array('cloudLocation', 'serverId', 'volumeId', 'mount', 'mountPoint')); $errmsg = null; try { $dbEbsVolume = DBEBSVolume::loadByVolumeId($this->getParam('volumeId')); if ($dbEbsVolume->isManual == 0) { $errmsg = sprintf(_("This volume was automatically created for role '%s' on farm '%s' and cannot be re-attahced manually."), $this->db->GetOne("\n SELECT name FROM roles\n JOIN farm_roles ON farm_roles.role_id = roles.id\n WHERE farm_roles.id=?\n LIMIT 1\n ", array($dbEbsVolume->farmRoleId)), $this->db->GetOne("SELECT name FROM farms WHERE id=? LIMIT 1", array($dbEbsVolume->farmId))); } } catch (Exception $e) { } if (!empty($errmsg)) { throw new Exception($errmsg); } /* @var $info VolumeData */ $info = $aws->ec2->volume->describe($this->getParam('volumeId'))->get(0); $dBServer = DBServer::LoadByID($this->getParam('serverId')); $image = Image::findOne([['platform' => $dBServer->platform], ['id' => $dBServer->imageId], ['cloudLocation' => $dBServer->GetCloudLocation()]]); $device = $dBServer->GetFreeDeviceName($image->isEc2HvmImage()); $res = $info->attach($dBServer->GetProperty(EC2_SERVER_PROPERTIES::INSTANCE_ID), $device); if ($this->getParam('attachOnBoot') == 'on') { $dbEbsVolume = new DBEBSVolume(); $dbEbsVolume->attachmentStatus = EC2_EBS_ATTACH_STATUS::ATTACHING; $dbEbsVolume->isManual = true; $dbEbsVolume->volumeId = $info->volumeId; $dbEbsVolume->ec2AvailZone = $info->availabilityZone; $dbEbsVolume->ec2Region = $this->getParam('cloudLocation'); $dbEbsVolume->deviceName = $device; $dbEbsVolume->farmId = $dBServer->farmId; $dbEbsVolume->farmRoleId = $dBServer->farmRoleId; $dbEbsVolume->serverId = $dBServer->serverId; $dbEbsVolume->serverIndex = $dBServer->index; $dbEbsVolume->size = $info->size; $dbEbsVolume->snapId = $info->snapshotId; $dbEbsVolume->mount = $this->getParam('mount') == 1; $dbEbsVolume->mountPoint = $this->getParam('mountPoint'); $dbEbsVolume->mountStatus = $this->getParam('mount') == 1 ? EC2_EBS_MOUNT_STATUS::AWAITING_ATTACHMENT : EC2_EBS_MOUNT_STATUS::NOT_MOUNTED; $dbEbsVolume->clientId = $this->user->getAccountId(); $dbEbsVolume->envId = $this->getEnvironmentId(); $dbEbsVolume->Save(); } $this->response->success('EBS volume has been successfully attached'); }
protected function run2() { $cnt = 0; $images = $this->db->GetAll('SELECT ri.*, r.env_id FROM role_images ri LEFT JOIN roles r ON r.id = ri.role_id'); foreach ($images as $i) { /* @var Image $imObj */ $i['env_id'] = $i['env_id'] == 0 ? NULL : $i['env_id']; $imObj = Image::findOne([['id' => $i['image_id']], ['$or' => [['envId' => $i['env_id']], ['envId' => null]]], ['platform' => $i['platform']], ['cloudLocation' => $i['cloud_location']]]); if (!$imObj) { $imObj = new Image(); $imObj->id = $i['image_id']; $imObj->envId = $i['env_id']; $imObj->platform = $i['platform']; $imObj->cloudLocation = $i['cloud_location']; $imObj->architecture = $i['architecture'] ? $i['architecture'] : 'x84_64'; $imObj->osId = $i['os_id']; $imObj->isDeprecated = 0; $imObj->dtAdded = NULL; $imObj->source = Image::SOURCE_MANUAL; if ($imObj->envId) { $imObj->checkImage(); } else { $imObj->status = Image::STATUS_ACTIVE; } if (is_null($imObj->status)) { $imObj->status = Image::STATUS_ACTIVE; } if (is_null($imObj->cloudLocation)) { $imObj->cloudLocation = ''; } $imObj->save(); $cnt++; } } $this->console->notice('Added %s images', $cnt); }
/** * @param string $platform Name of platform * @param string $cloudLocation Name of location * @param array $ids The list of the identifiers of the cloud instances * @param int $roleId optional Identifier of Role * @return array * @throws Exception */ public function checkStatus($platform, $cloudLocation, $ids, $roleId = null) { if (!in_array($platform, $this->allowedPlatforms)) { throw new Exception(sprintf("Platform '%s' is not supported", $platform)); } if (!$this->environment->isPlatformEnabled($platform)) { throw new Exception(sprintf("Platform '%s' is not enabled", $platform)); } if (empty($ids) || empty($ids[0])) { throw new Exception("You should provide at least one instanceId"); } $instances = PlatformFactory::NewPlatform($platform)->getOrphanedServers($this->getEnvironmentEntity(), $cloudLocation, $ids); $status = ['instances' => $instances]; $imageIds = array_unique(array_map(function ($item) { return $item->imageId; }, $instances)); if (count($imageIds) != 1) { $status['compatibility'] = ['success' => false]; return $status; } /* @var $instance OrphanedServer */ $instance = $instances[0]; $status['compatibility'] = ['success' => true]; // Check vpc compatibility if ($instance->vpcId && $instance->subnetId) { $gov = new Scalr_Governance($this->getEnvironmentId()); $vpcGovernanceRegions = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'regions'); if (isset($vpcGovernanceRegions)) { if (!array_key_exists($cloudLocation, $vpcGovernanceRegions)) { $status['compatibility']['success'] = false; $status['compatibility']['message'] = sprintf('Region <b>%s</b> is not allowed by the Governance.', $cloudLocation); } else { $vpcGovernanceIds = $vpcGovernanceRegions[$cloudLocation]['ids']; if (!empty($vpcGovernanceIds) && !in_array($instance->vpcId, $vpcGovernanceIds)) { $status['compatibility']['success'] = false; $status['compatibility']['message'] = sprintf('VPC <b>%s</b> is not allowed by the Governance.', $instance->vpcId); } else { $vpcGovernanceIds = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'ids'); /* @var $platformObject Ec2PlatformModule */ $platformObject = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); $subnet = $platformObject->listSubnets($this->getEnvironment(), $cloudLocation, $instance->vpcId, true, $instance->subnetId); if (isset($vpcGovernanceIds[$instance->vpcId])) { if (!empty($vpcGovernanceIds[$instance->vpcId]) && is_array($vpcGovernanceIds[$instance->vpcId]) && !in_array($instance->subnetId, $vpcGovernanceIds[$instance->vpcId])) { $status['compatibility']['success'] = false; $status['compatibility']['message'] = sprintf('Subnet <b>%s</b> is prohibited by the Governance.', $instance->subnetId); } else { if ($vpcGovernanceIds[$instance->vpcId] == "outbound-only" && $subnet['type'] != 'private') { $status['compatibility']['success'] = false; $status['compatibility']['message'] = 'Only private subnets are allowed by the Governance.'; } else { if ($vpcGovernanceIds[$instance->vpcId] == "full" && $subnet['type'] != 'public') { $status['compatibility']['success'] = false; $status['compatibility']['message'] = 'Only public subnets are allowed by the Governance.'; } } } } } } } } if (!$status['compatibility']['success']) { return $status; } $scopeCriteria = ['$or' => [['accountId' => null], ['$and' => [['accountId' => $this->getUser()->accountId], ['$or' => [['envId' => null], ['envId' => $this->getEnvironment()->id]]]]]]]; /* @var $image Entity\Image */ $image = Entity\Image::findOne([['platform' => $platform], ['cloudLocation' => $cloudLocation], ['id' => $instance->imageId], $scopeCriteria]); $status['image'] = ['success' => !!$image, 'data' => ['id' => $instance->imageId]]; if ($image) { if ($image->isScalarized) { $status['image']['success'] = false; $status['image']['isScalarized'] = true; return $status; } $status['image']['data'] = ['hash' => $image->hash, 'name' => $image->name, 'id' => $image->id, 'scope' => $image->getScope()]; $criteria = [['platform' => $platform], ['imageId' => $image->id]]; if (!($platform == SERVER_PLATFORMS::GCE || $platform == SERVER_PLATFORMS::AZURE)) { $criteria[] = ['cloudLocation' => $cloudLocation]; } $roleIds = []; foreach (Entity\RoleImage::find($criteria) as $ri) { $roleIds[] = $ri->roleId; } if (count($roleIds)) { $roles = Entity\Role::find([['id' => ['$in' => $roleIds]], ['isScalarized' => false], $scopeCriteria]); $status['role'] = ['availableRoles' => [], 'image' => Scalr_UI_Controller_Images::controller()->convertEntityToArray($image)]; $selectedRole = null; if (count($roles) == 1) { $selectedRole = $roles->current(); } else { if ($roleId && in_array($roleId, $roleIds)) { foreach ($roles as $role) { /* @var $role Entity\Role */ if ($role->id == $roleId) { $selectedRole = $role; break; } } } } foreach ($roles as $role) { /* @var $role Entity\Role */ $status['role']['availableRoles'][] = ['id' => $role->id, 'name' => $role->name, 'scope' => $role->getScope()]; } if ($selectedRole) { $status['role']['success'] = true; $status['role']['data'] = ['id' => $selectedRole->id, 'name' => $selectedRole->name, 'scope' => $selectedRole->getScope()]; $farms = []; $status['farmrole'] = ['instance' => ['instanceType' => $instance->instanceType, 'vpcId' => $instance->vpcId, 'subnetId' => $instance->subnetId, 'roleName' => $selectedRole->name]]; foreach (Entity\Farm::find([['envId' => $this->getEnvironment()->id], ['status' => FARM_STATUS::RUNNING]]) as $farm) { /* @var $farm Entity\Farm */ if ($this->request->hasPermissions($farm, Acl::PERM_FARMS_UPDATE) && $this->request->hasPermissions($farm, Acl::PERM_FARMS_SERVERS)) { // cloud specific (EC2) if ($farm->settings[Entity\FarmSetting::EC2_VPC_ID] == $instance->vpcId) { $farms[$farm->id] = ['id' => $farm->id, 'name' => $farm->name, 'farmroles' => []]; } } } foreach (Entity\FarmRole::find([['farmId' => ['$in' => array_keys($farms)]], ['roleId' => $selectedRole->id]]) as $farmRole) { /* @var $farmRole Entity\FarmRole */ if (isset($farms[$farmRole->farmId])) { if (!$instance->subnetId || $instance->subnetId && in_array($instance->subnetId, json_decode($farmRole->settings[Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID]))) { $farms[$farmRole->farmId]['farmroles'][] = ['id' => $farmRole->id, 'name' => $farmRole->alias, 'tags' => $farmRole->getCloudTags(true)]; } } } $status['farmrole']['data'] = array_values($farms); $status['farmrole']['success'] = false; } else { if (count($roles) > 1) { $status['role']['success'] = false; } else { $status['role']['success'] = false; } } } else { $status['role']['success'] = false; $status['role']['image'] = Scalr_UI_Controller_Images::controller()->convertEntityToArray($image); } } return $status; }
protected function run4() { $this->console->notice('Fix shared images, remove duplicates'); foreach ($this->db->GetAll('SELECT id, platform, cloud_location FROM images GROUP BY id HAVING count(*) > 1') as $im) { if ($this->db->GetOne('SELECT 1 FROM images WHERE id = ? and platform = ? and cloud_location = ? and env_id is null', [$im['id'], $im['platform'], $im['cloud_location']])) { $size = $this->db->GetRow('SELECT `size`, name, architecture FROM images WHERE id = ? and platform = ? and cloud_location = ? and size > 0', [$im['id'], $im['platform'], $im['cloud_location']]); if ($size) { $this->db->Execute('UPDATE images SET size = ? WHERE id = ? and platform = ? and cloud_location = ? and env_id is null', [$size['size'], $im['id'], $im['platform'], $im['cloud_location']]); if ($size['architecture']) { $this->db->Execute('UPDATE images SET architecture = ? WHERE id = ? and platform = ? and cloud_location = ? and env_id is null', [$size['architecture'], $im['id'], $im['platform'], $im['cloud_location']]); } if ($size['name']) { $this->db->Execute('UPDATE images SET name = ? WHERE id = ? and platform = ? and cloud_location = ? and env_id is null', [$size['name'], $im['id'], $im['platform'], $im['cloud_location']]); } } // found shared image, remove others $this->db->Execute('DELETE FROM images WHERE id = ? and platform = ? and cloud_location = ? and env_id is not null', [$im['id'], $im['platform'], $im['cloud_location']]); } } $this->console->notice('Fill shared images with info'); foreach ($this->db->GetAll('SELECT * FROM roles WHERE env_id = 0') as $role) { $hvm = stristr($role['name'], '-hvm-') ? 1 : 0; $architecture = ''; if (stristr($role['name'], '64-')) { $architecture = 'x86_64'; } if (stristr($role['name'], 'i386')) { $architecture = 'i386'; } foreach ($this->db->GetAll('SELECT * FROM role_images WHERE role_id = ?', [$role['id']]) as $im) { /* @var Image $image */ $image = Image::findOne([['id' => $im['image_id']], ['platform' => $im['platform']], ['cloudLocation' => $im['cloud_location']], ['envId' => null]]); if ($image) { if ($architecture) { $image->architecture = $architecture; } else { if (!$image->architecture) { $image->architecture = 'i386'; } } $image->osId = $role['osId']; if ($image->name == $image->id && $role['name']) { $image->name = $role['name']; } if ($hvm) { $image->type = 'ebs-hvm'; } else { $image->type = 'ebs'; } $image->save(); } else { $this->console->warning('Image not found: %s, %s, %s', $im['platform'], $im['cloud_location'], $im['image_id']); } } } }
/** * @return Image|NULL * @throws \Exception */ public function getImage() { /* @var $role Role */ $role = Role::findPk($this->roleId); return Image::findOne([['id' => $this->imageId], ['$or' => [['envId' => $role->envId == 0 ? null : $role->envId], ['envId' => null]]], ['platform' => $this->platform], ['cloudLocation' => $this->cloudLocation]]); }
/** * @param string $imageId * @param string $platform * @param string $osId * @param string $name * @param string $cloudLocation * @param string $architecture * @param int $size * @param string $ec2Type * @param bool $ec2Hvm * @param JsonData $software * @throws Scalr_Exception_Core */ public function xSaveAction($imageId, $platform, $osId, $name, $cloudLocation = '', $architecture = '', $size = null, $ec2Type = null, $ec2Hvm = null, JsonData $software = null) { $this->restrictAccess('IMAGES', 'MANAGE'); if ($platform == SERVER_PLATFORMS::GCE || $platform == SERVER_PLATFORMS::AZURE) { $cloudLocation = ''; } if ($accountId = $this->user->getAccountId()) { if ($envId = $this->getEnvironmentId(true)) { if (Image::findOne([['id' => $imageId], ['envId' => $envId], ['platform' => $platform], ['cloudLocation' => $cloudLocation]])) { throw new Scalr_Exception_Core('This Image has already been registered in the Environment Scope.'); } } if (Image::findOne([['id' => $imageId], ['accountId' => $this->user->getAccountId()], ['envId' => null], ['platform' => $platform], ['cloudLocation' => $cloudLocation]])) { throw new Scalr_Exception_Core('This Image has already been registered in the Account Scope.'); } } if (Image::findOne([['id' => $imageId], ['accountId' => null], ['platform' => $platform], ['cloudLocation' => $cloudLocation]])) { $this->response->failure('This Image has already been registered in the Scalr Scope.'); return; } if (!Role::isValidName($name)) { $this->response->failure('Name should start and end with letter or number and contain only letters, numbers and dashes.'); return; } $image = new Image(); $image->accountId = $this->user->getAccountId() ?: null; $image->envId = $this->getEnvironmentId(true); $image->id = $imageId; $image->platform = $platform; $image->cloudLocation = $cloudLocation; $image->architecture = 'x86_64'; if ($this->request->getScope() == ScopeInterface::SCOPE_ENVIRONMENT) { if ($image->checkImage() === false) { $this->response->failure("This Image does not exist, or isn't usable by your account"); return; } } else { $image->architecture = $architecture; $image->size = $size; if ($platform == SERVER_PLATFORMS::EC2) { if ($ec2Type == 'ebs' || $ec2Type == 'instance-store') { $image->type = $ec2Type; if ($ec2Hvm) { $image->type = $image->type . '-hvm'; } } } } $image->name = $name; $image->source = Image::SOURCE_MANUAL; $image->osId = $osId; $image->createdById = $this->user->getId(); $image->createdByEmail = $this->user->getEmail(); $image->status = Image::STATUS_ACTIVE; $image->save(); $props = []; foreach ($software as $value) { $props[$value] = null; } $image->setSoftware($props); $this->response->data(['hash' => $image->hash]); $this->response->success('Image has been added'); }
/** * Attaches volume to server * * It uses request params and can't be used without UI request * * @param VolumeData $info AWS EBS Volume info * @throws Exception */ protected function attachVolumeToServer(VolumeData $info) { $dBServer = DBServer::LoadByID($this->getParam('serverId')); //Check access permission to specified server $this->request->checkPermissions($dBServer->GetFarmObject()->__getNewFarmObject(), Acl::PERM_FARMS_SERVERS); $errmsg = null; try { $dbEbsVolume = DBEBSVolume::loadByVolumeId($this->getParam('volumeId')); if ($dbEbsVolume->isManual == 0) { $errmsg = sprintf(_("This volume was automatically created for role '%s' on farm '%s' and cannot be re-attahced manually."), $this->db->GetOne("\n SELECT name FROM roles\n JOIN farm_roles ON farm_roles.role_id = roles.id\n WHERE farm_roles.id=?\n LIMIT 1\n ", array($dbEbsVolume->farmRoleId)), $this->db->GetOne("SELECT name FROM farms WHERE id=? LIMIT 1", array($dbEbsVolume->farmId))); } } catch (Exception $e) { } if (!empty($errmsg)) { throw new Exception($errmsg); } $image = Image::findOne([['platform' => $dBServer->platform], ['id' => $dBServer->imageId], ['cloudLocation' => $dBServer->GetCloudLocation()]]); $device = $dBServer->GetFreeDeviceName($image->isEc2HvmImage()); $res = $info->attach($dBServer->GetProperty(EC2_SERVER_PROPERTIES::INSTANCE_ID), $device); if ($this->getParam('attachOnBoot') == 'on') { $dbEbsVolume = new DBEBSVolume(); $dbEbsVolume->attachmentStatus = EC2_EBS_ATTACH_STATUS::ATTACHING; $dbEbsVolume->isManual = true; $dbEbsVolume->volumeId = $info->volumeId; $dbEbsVolume->ec2AvailZone = $info->availabilityZone; $dbEbsVolume->ec2Region = $this->getParam('cloudLocation'); $dbEbsVolume->deviceName = $device; $dbEbsVolume->farmId = $dBServer->farmId; $dbEbsVolume->farmRoleId = $dBServer->farmRoleId; $dbEbsVolume->serverId = $dBServer->serverId; $dbEbsVolume->serverIndex = $dBServer->index; $dbEbsVolume->size = $info->size; $dbEbsVolume->snapId = $info->snapshotId; $dbEbsVolume->mount = $this->getParam('mount') == 1; $dbEbsVolume->mountPoint = $this->getParam('mountPoint'); $dbEbsVolume->mountStatus = $this->getParam('mount') == 1 ? EC2_EBS_MOUNT_STATUS::AWAITING_ATTACHMENT : EC2_EBS_MOUNT_STATUS::NOT_MOUNTED; $dbEbsVolume->clientId = $this->user->getAccountId(); $dbEbsVolume->envId = $this->getEnvironmentId(); $dbEbsVolume->Save(); } //Updates/Creates AWS Tags of Volume $tags = []; foreach ($dBServer->getAwsTags() as $k => $v) { $tags[] = ['key' => $k, 'value' => $v]; } if (!empty($tags)) { $info->createTags($tags); } }
public function xSuspendServersAction() { $this->request->defineParams(array('servers' => array('type' => 'json'))); $errorServers = array(); foreach ($this->getParam('servers') as $serverId) { try { $dbServer = DBServer::LoadByID($serverId); $this->user->getPermissions()->validate($dbServer); if ($dbServer->platform == SERVER_PLATFORMS::AZURE || $dbServer->platform == SERVER_PLATFORMS::CLOUDSTACK || $dbServer->platform == SERVER_PLATFORMS::GCE || $dbServer->platform == SERVER_PLATFORMS::EC2 || PlatformFactory::isOpenstack($dbServer->platform)) { /* @var $image Image */ if ($dbServer->platform == SERVER_PLATFORMS::EC2 && ($image = Image::findOne([['platform' => $dbServer->platform], ['cloudLocation' => $dbServer->cloudLocation], ['id' => $dbServer->imageId], ['$or' => [['accountId' => null], ['accountId' => $dbServer->clientId]]], ['$or' => [['envId' => null], ['envId' => $dbServer->envId]]]])) && $image->isEc2InstanceStoreImage()) { $errorServers[] = "The instance does not have an 'ebs' root device type and cannot be stopped"; continue; } if ($dbServer->farmRoleId) { if ($this->hasDatabaseBehavior($dbServer->GetFarmRoleObject()->GetRoleObject()->getBehaviors())) { $errors[] = "Database instance cannot be stopped"; continue; } if ($dbServer->GetFarmRoleObject()->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $errors[] = "RabbitMQ instance cannot be stopped"; continue; } } $dbServer->suspend('', false, $this->user); } else { //NOT SUPPORTED } } catch (Exception $e) { } } $this->response->data(array('data' => $errorServers)); }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Entity\Image) { throw new \InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Image class")); } if ($entity->hash !== null) { //Checks if the image does exist if (!Entity\Image::findPk($entity->hash)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Image with ID: %d", $entity->hash)); } } else { $image = Entity\Image::findOne([['id' => $entity->id], ['platform' => $entity->platform], ['cloudLocation' => (string) $entity->cloudLocation], ['$or' => [['accountId' => null], ['$and' => [['accountId' => $entity->accountId], ['$or' => [['envId' => null], ['envId' => $entity->envId]]]]]]]]); if ($image) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "This Image has already been registered in Scalr"); } } //Is this a new Image if (!$entity->hash) { $entity->createdByEmail = $this->controller->getUser()->email; $entity->createdById = $this->controller->getUser()->id; } if (!Entity\Role::isValidName($entity->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid name of the Image"); } if (empty($entity->architecture)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property 'architecture'"); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } //We only allow to either create or modify Environment Scope Roles if ($entity->getScope() !== $this->controller->getScope()) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, sprintf("Invalid scope")); } if (empty($entity->osId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property 'os.id'"); } //Tries to find out the specified OS if (empty(Entity\Os::findPk($entity->osId))) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "OS with id '{$entity->osId}' not found."); } if (empty($entity->platform)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property platform"); } if (!isset(SERVER_PLATFORMS::GetList()[$entity->platform])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Unexpected platform value"); } }
/** * Get Image entity * * @return Image|null Return Image entity or null */ public function getImage() { if (!empty($this->imageId) && empty($this->_image)) { $this->_image = Image::findOne([['platform' => $this->platform], ['cloudLocation' => in_array($this->platform, [SERVER_PLATFORMS::GCE, SERVER_PLATFORMS::AZURE]) ? '' : $this->cloudLocation], ['id' => $this->imageId], ['$or' => [['accountId' => null], ['$and' => [['accountId' => $this->accountId], ['$or' => [['envId' => $this->envId], ['envId' => null]]]]]]]], null, ['envId' => false]); } return $this->_image; }
/** * Creates and save RoleImage entity with data from fixtures * * @param string $name Role category data name */ protected function prepareRoleImage($name) { foreach ($this->sets[$name] as &$roleImageData) { if (in_array($roleImageData['platform'], [SERVER_PLATFORMS::GCE, SERVER_PLATFORMS::AZURE])) { $roleImageData['cloudLocation'] = ''; } /* @var $image Entity\Image */ $image = Entity\Image::findOne([['cloudLocation' => $roleImageData['cloudLocation']], ['platform' => $roleImageData['platform']], ['$or' => [['accountId' => static::$user->getAccountId()], ['accountId' => null]]]]); if (empty($image)) { ApiTest::markTestIncomplete(sprintf('Image with cloudLocation %s and platform %s not isset', $roleImageData['cloudLocation'], $roleImageData['platform'])); } $roleImageData['imageId'] = $image->id; ApiTest::createEntity(new Entity\RoleImage(), $roleImageData); } }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Entity\Image) { throw new \InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Image class")); } if ($entity->hash !== null) { //Checks if the image does exist if (!Entity\Image::findPk($entity->hash)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Image with ID: %d", $entity->hash)); } } else { $image = Entity\Image::findOne([['id' => $entity->id], ['$or' => [['envId' => $entity->envId], ['envId' => null]]], ['platform' => $entity->platform], ['cloudLocation' => $entity->cloudLocation]]); if ($image) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "This Image has already been registered in Scalr"); } } //Is this a new Image if (!$entity->hash) { $entity->createdByEmail = $this->controller->getUser()->email; $entity->createdById = $this->controller->getUser()->id; } if (!Entity\Role::validateName($entity->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid name of the Image"); } $entity->architecture = $entity->architecture ?: 'x86_64'; if (!in_array($entity->architecture, ['i386', 'x86_64'])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid architecture of the Image."); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } //We only allow to either create or modify Environment Scope Roles if ($entity->getScope() !== ScopeInterface::SCOPE_ENVIRONMENT) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, sprintf("Only %s scope is allowed.", ScopeInterface::SCOPE_ENVIRONMENT)); } //Validates OS if (!empty($entity->osId)) { //Tries to find out the specified OS $os = Entity\Os::findPk($entity->osId); if (!$os instanceof Entity\Os) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Specified OS does not exist"); } } else { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "OS must be provided with the request."); } }
/** * Associates a new Image with the Role * * @param int $roleId The Identifier of the role * @param string $imageId The Identifier of the image * @return \Scalr\Api\DataType\ResultEnvelope * @throws ApiErrorException */ public function replaceImageAction($roleId, $imageId) { $this->checkScopedPermissions('ROLES', 'MANAGE'); $role = $this->getRole($roleId, true); $oldImage = $this->getImage($roleId, $imageId); $object = $this->request->getJsonBody(); $objectImageId = static::getBareId($object, 'image'); $objectRoleId = static::getBareId($object, 'role'); if (empty($objectImageId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Invalid body"); } if (!preg_match('/' . ApiApplication::REGEXP_UUID . '/', $objectImageId) || $oldImage->hash == $objectImageId) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid image identifier"); } if (!empty($objectRoleId) && $roleId != $objectRoleId) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the role"); } if (is_object($object->image)) { $imageAdapter = $this->adapter('image'); //Pre validates the request object $imageAdapter->validateObject($object->image); } $criteria = $this->getScopeCriteria(); $criteria[] = ['hash' => $objectImageId]; /* @var $image Entity\Image */ $image = Entity\Image::findOne($criteria); if (empty($image)) { throw new ApiErrorException(404, ErrorMessage::ERR_INVALID_VALUE, "The Image either does not exist or isn't in scope for the current Environment."); } if ($image->cloudLocation !== $oldImage->cloudLocation) { throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, "You can only replace images with equal cloud locations"); } $this->setImage($role, $image->platform, $image->cloudLocation, $image->id, $this->getUser()->id, $this->getUser()->email); $this->response->setStatus(200); return $this->result(['image' => ['id' => $image->hash], 'role' => ['id' => $role->id]]); }
/** * @test */ public function testImagesFunctional() { $testName = str_replace('-', '', $this->getTestName()); $images = null; $uri = self::getUserApiUrl('/images'); do { $query = []; if (isset($images->pagination->next)) { $parts = parse_url($images->pagination->next); parse_str($parts['query'], $query); } $describe = $this->request($uri, Request::METHOD_GET, $query); $this->assertDescribeResponseNotEmpty($describe); $images = $describe->getBody(); foreach ($images->data as $image) { $this->assertImageObjectNotEmpty($image); if (strpos($image->name, $testName) !== false) { $delete = $this->request($uri . '/' . $image->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->response->getStatus()); } } } while (!empty($images->pagination->next)); // test create action $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => 'invalid']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid scope'); $create = $this->request($uri, Request::METHOD_POST); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body'); $create = $this->request($uri, Request::METHOD_POST, [], ['invalid' => 'value']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => 'invalidName^$&&']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid name of the Image'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'architecture' => 'invalid', 'name' => $testName]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid architecture of the Image'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'OS must be provided with the request'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => 'invalidOsId']]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Specified OS does not exist'); $os = Os::findOne([['status' => Os::STATUS_ACTIVE]]); /* @var $os Os */ $env = \Scalr_Environment::init()->loadById(static::$testEnvId); $platform = \SERVER_PLATFORMS::EC2; if ($env->isPlatformEnabled($platform)) { $env->setPlatformConfig([$platform . '.is_enabled' => 0]); } $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $os->id], 'cloudPlatform' => $platform]); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $create); $this->assertErrorMessageStatusEquals(400, $create); $env->setPlatformConfig([$platform . '.is_enabled' => 1]); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['invalid'], 'cloudPlatform' => $platform]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid identifier of the OS'); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $os->id], 'cloudPlatform' => $platform]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Unable to find the requested image on the cloud'); $region = null; $cloudImageId = null; foreach (Aws::getCloudLocations() as $cloudLocation) { $cloudImageId = $this->getNewImageId($env, $cloudLocation); if (!empty($cloudImageId)) { $region = $cloudLocation; break; } } $this->assertNotNull($cloudImageId); $this->assertNotNull($cloudLocation); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => $os->id, 'cloudPlatform' => $platform, 'cloudLocation' => $region, 'cloudImageId' => $cloudImageId]); $this->assertFetchResponseNotEmpty($create); $imageBody = $create->getBody(); $this->assertImageObjectNotEmpty($imageBody->data); $this->assertEquals(201, $create->response->getStatus()); $this->assertNotEmpty($imageBody->data->id); $this->assertEquals(ScopeInterface::SCOPE_ENVIRONMENT, $imageBody->data->scope); $this->assertEquals($testName, $imageBody->data->name); $this->assertEquals($os->id, $imageBody->data->os->id); $this->assertEquals($platform, $imageBody->data->cloudPlatform); $this->assertEquals($region, $imageBody->data->cloudLocation); $this->assertEquals($cloudImageId, $imageBody->data->cloudImageId); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $os->id], 'cloudPlatform' => $platform, 'cloudLocation' => $region, 'cloudImageId' => $cloudImageId]); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_UNICITY_VIOLATION, $create); $this->assertErrorMessageStatusEquals(409, $create); // test filtering $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_ENVIRONMENT]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertImageObjectNotEmpty($data); $this->assertEquals(ScopeInterface::SCOPE_ENVIRONMENT, $data->scope); } $describe = $this->request($uri, Request::METHOD_GET, ['name' => $testName]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertImageObjectNotEmpty($data); $this->assertEquals($testName, $data->name); } $describe = $this->request($uri, Request::METHOD_GET, ['id' => $imageBody->data->id]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertImageObjectNotEmpty($data); $this->assertEquals($imageBody->data->id, $data->id); } $describe = $this->request($uri, Request::METHOD_GET, ['os' => $os->id]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertImageObjectNotEmpty($data); $this->assertEquals($os->id, $data->os->id); } $describe = $this->request($uri, Request::METHOD_GET, ['os' => 'invalid*&^^%']); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the OS"); $describe = $this->request($uri, Request::METHOD_GET, ['cloudPlatform' => $platform, 'cloudLocation' => $region]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertImageObjectNotEmpty($data); $this->assertEquals($platform, $data->cloudPlatform); $this->assertEquals($region, $data->cloudLocation); } $describe = $this->request($uri, Request::METHOD_GET, ['cloudLocation' => $region]); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $describe); $this->assertErrorMessageStatusEquals(400, $describe); $describe = $this->request($uri, Request::METHOD_GET, ['cloudImageId' => $cloudImageId]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertImageObjectNotEmpty($data); $this->assertEquals($cloudImageId, $data->cloudImageId); } // test modify action $modify = $this->request($uri, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_ENDPOINT_NOT_FOUND, $modify); $this->assertErrorMessageStatusEquals(404, $modify); $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['invalid' => $testName . 'modify']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $modify); $this->assertErrorMessageStatusEquals(400, $modify); $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['id' => $testName . 'modify']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $modify); $this->assertErrorMessageStatusEquals(400, $modify); $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['scope' => $testName . 'modify']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $modify); $this->assertErrorMessageStatusEquals(400, $modify); $notFoundId = '11111111-1111-1111-1111-111111111111'; $modify = $this->request($uri . '/' . $notFoundId, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_OBJECT_NOT_FOUND, $modify); $this->assertErrorMessageStatusEquals(404, $modify); $entity = Image::findOne([['envId' => null], ['status' => Image::STATUS_ACTIVE]]); /* @var $entity Image */ $this->assertNotEmpty($entity); $notAccessibleId = $entity->hash; $modify = $this->request($uri . '/' . $notAccessibleId, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_SCOPE_VIOLATION, $modify); $this->assertErrorMessageStatusEquals(403, $modify); $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $entity->osId], 'cloudPlatform' => $entity->platform, 'cloudLocation' => $entity->cloudLocation, 'cloudImageId' => $entity->id]); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_UNICITY_VIOLATION, $create); $this->assertErrorMessageStatusEquals(409, $create); // test fetch action $fetch = $this->request($uri . '/' . $notFoundId, Request::METHOD_GET); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_OBJECT_NOT_FOUND, $fetch); $this->assertErrorMessageStatusEquals(404, $fetch); $fetch = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_GET); $this->assertFetchResponseNotEmpty($fetch); $fetchBody = $fetch->getBody(); $this->assertImageObjectNotEmpty($fetchBody->data); $this->assertEquals($imageBody->data->id, $fetchBody->data->id); $fetch = $this->request($uri . '/' . $entity->hash, Request::METHOD_GET); $this->assertFetchResponseNotEmpty($fetch); $fetchBody = $fetch->getBody(); $this->assertImageObjectNotEmpty($fetchBody->data); $this->assertEquals($entity->hash, $fetchBody->data->id); $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']); $this->assertEquals(200, $modify->response->getStatus()); $this->assertImageObjectNotEmpty($modify->getBody()->data); $this->assertEquals($testName . 'modify', $modify->getBody()->data->name); // test copy action $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $copy); $this->assertErrorMessageStatusEquals(400, $copy); $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => 'invalid', 'cloudPlatform' => 'ec2']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $copy); $this->assertErrorMessageStatusEquals(400, $copy); $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => Aws::REGION_US_EAST_1, 'cloudPlatform' => 'gce']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $copy); $this->assertErrorMessageStatusEquals(400, $copy); $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => $region, 'cloudPlatform' => 'ec2']); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_BAD_REQUEST, $copy); $this->assertErrorMessageStatusEquals(400, $copy); $awsRegions = Aws::getCloudLocations(); $copyTo = null; foreach ($awsRegions as $awsRegion) { if ($awsRegion != $region) { $copyTo = $awsRegion; break; } } $this->assertNotNull($copyTo); $copy = $this->request($uri . '/' . $notAccessibleId . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => $copyTo, 'cloudPlatform' => \SERVER_PLATFORMS::EC2]); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_SCOPE_VIOLATION, $copy); $this->assertErrorMessageStatusEquals(403, $copy); $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => $copyTo, 'cloudPlatform' => \SERVER_PLATFORMS::EC2]); $copyBody = $copy->getBody(); $this->assertEquals(202, $copy->response->getStatus()); $this->assertFetchResponseNotEmpty($copy); $this->assertImageObjectNotEmpty($copyBody->data); $this->assertEquals(\SERVER_PLATFORMS::EC2, $copyBody->data->cloudPlatform); $this->assertEquals($copyTo, $copyBody->data->cloudLocation); // test delete action $delete = $this->request($uri . '/' . $notFoundId, Request::METHOD_DELETE); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_OBJECT_NOT_FOUND, $delete); $this->assertErrorMessageStatusEquals(404, $delete); $delete = $this->request($uri . '/' . $entity->hash, Request::METHOD_DELETE); $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_SCOPE_VIOLATION, $delete); $this->assertErrorMessageStatusEquals(403, $delete); $delete = $this->request($uri . '/' . $copyBody->data->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->response->getStatus()); $delete = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->response->getStatus()); }
/** * @return Image */ public function getImageEntity() { return Image::findOne([['id' => $this->snapshotId], ['envId' => $this->envId], ['platform' => $this->platform], ['cloudLocation' => $this->cloudLocation]]); }
/** * Launches server * * @param \ServerCreateInfo $ServerCreateInfo optional The server create info * @param \DBServer $DBServer optional The DBServer object * @param bool $delayed optional * @param integer|array $reason optional * @param \Scalr_Account_User|int $user optional The Scalr_Account_User object or its unique identifier * @return DBServer|null Returns the DBServer object on cussess or null otherwise */ public static function LaunchServer(ServerCreateInfo $ServerCreateInfo = null, DBServer $DBServer = null, $delayed = false, $reason = 0, $user = null) { $db = self::getDb(); $farm = null; //Ensures handling identifier of the user instead of the object if ($user !== null && !$user instanceof \Scalr_Account_User) { try { $user = Scalr_Account_User::init()->loadById(intval($user)); } catch (\Exception $e) { } } if (!$DBServer && $ServerCreateInfo) { $ServerCreateInfo->SetProperties(array(SERVER_PROPERTIES::SZR_KEY => Scalr::GenerateRandomKey(40), SERVER_PROPERTIES::SZR_KEY_TYPE => SZR_KEY_TYPE::ONE_TIME)); $DBServer = DBServer::Create($ServerCreateInfo, false, true); } elseif (!$DBServer && !$ServerCreateInfo) { // incorrect arguments Logger::getLogger(LOG_CATEGORY::FARM)->error(sprintf("Cannot create server")); return null; } $propsToSet = array(); if ($user instanceof \Scalr_Account_User) { $propsToSet[SERVER_PROPERTIES::LAUNCHED_BY_ID] = $user->id; $propsToSet[SERVER_PROPERTIES::LAUNCHED_BY_EMAIL] = $user->getEmail(); } //We should keep role_id and farm_role_id in server properties to use in cost analytics if (!empty($DBServer->farmRoleId)) { $propsToSet[SERVER_PROPERTIES::FARM_ROLE_ID] = $DBServer->farmRoleId; $propsToSet[SERVER_PROPERTIES::ROLE_ID] = $DBServer->farmRoleId ? $DBServer->GetFarmRoleObject()->RoleID : 0; } try { // Ensures the farm object will be fetched as correctly as possible $farm = $DBServer->farmId ? $DBServer->GetFarmObject() : null; $farmRole = $DBServer->farmRoleId ? $DBServer->GetFarmRoleObject() : null; if (!$farmRole instanceof DBFarmRole) { $farmRole = null; } else { if (!$farm instanceof DBFarm) { // Gets farm through FarmRole object in this case $farm = $farmRole->GetFarmObject(); } } if ($farm instanceof DBFarm) { $propsToSet[SERVER_PROPERTIES::FARM_CREATED_BY_ID] = $farm->createdByUserId; $propsToSet[SERVER_PROPERTIES::FARM_CREATED_BY_EMAIL] = $farm->createdByUserEmail; $projectId = $farm->GetSetting(DBFarm::SETTING_PROJECT_ID); if (!empty($projectId)) { try { $projectEntity = ProjectEntity::findPk($projectId); if ($projectEntity instanceof ProjectEntity) { /* @var $projectEntity ProjectEntity */ $ccId = $projectEntity->ccId; } else { $projectId = null; } } catch (Exception $e) { $projectId = null; } } $propsToSet[SERVER_PROPERTIES::FARM_PROJECT_ID] = $projectId; } if ($farmRole instanceof DBFarmRole) { $propsToSet[SERVER_PROPERTIES::INFO_INSTANCE_TYPE_NAME] = $farmRole->GetSetting(DBFarmRole::SETTING_INFO_INSTANCE_TYPE_NAME); } if (!empty($ccId)) { $propsToSet[SERVER_PROPERTIES::ENV_CC_ID] = $ccId; } elseif ($DBServer->envId && ($environment = $DBServer->GetEnvironmentObject()) instanceof Scalr_Environment) { $propsToSet[SERVER_PROPERTIES::ENV_CC_ID] = $environment->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID); } } catch (Exception $e) { Logger::getLogger(LOG_CATEGORY::FARM)->error(sprintf("Could not load related object for recently created server %s. It says: %s", $DBServer->serverId, $e->getMessage())); } if (!empty($propsToSet)) { $DBServer->SetProperties($propsToSet); } $fnGetReason = function ($reasonId) { $args = func_get_args(); $args[0] = DBServer::getLaunchReason($reasonId); return [call_user_func_array('sprintf', $args), $reasonId]; }; if ($delayed) { $DBServer->status = SERVER_STATUS::PENDING_LAUNCH; list($reasonMsg, $reasonId) = is_array($reason) ? call_user_func_array($fnGetReason, $reason) : $fnGetReason($reason); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_REASON => $reasonMsg, SERVER_PROPERTIES::LAUNCH_REASON_ID => $reasonId]); $DBServer->Save(); return $DBServer; } if ($ServerCreateInfo && $ServerCreateInfo->roleId) { $dbRole = DBRole::loadById($ServerCreateInfo->roleId); if ($dbRole->generation == 1) { $DBServer->status = SERVER_STATUS::PENDING_LAUNCH; $DBServer->Save(); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_ERROR => "ami-scripts servers no longer supported", SERVER_PROPERTIES::LAUNCH_ATTEMPT => $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ATTEMPT) + 1, SERVER_PROPERTIES::LAUNCH_LAST_TRY => (new DateTime())->format('Y-m-d H:i:s')]); return $DBServer; } } // Limit amount of pending servers if ($DBServer->isOpenstack()) { $config = \Scalr::getContainer()->config; if ($config->defined("scalr.{$DBServer->platform}.pending_servers_limit")) { $pendingServersLimit = $config->get("scalr.{$DBServer->platform}.pending_servers_limit"); $pendingServers = $db->GetOne("SELECT COUNT(*) FROM servers WHERE platform=? AND status=? AND server_id != ?", array($DBServer->platform, SERVER_STATUS::PENDING, $DBServer->serverId)); if ($pendingServers >= $pendingServersLimit) { Logger::getLogger("SERVER_LAUNCH")->warn("{$pendingServers} servers in PENDING state on {$DBServer->platform}. Limit is: {$pendingServersLimit}. Waiting."); $DBServer->status = SERVER_STATUS::PENDING_LAUNCH; $DBServer->Save(); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_ATTEMPT => $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ATTEMPT) + 1, SERVER_PROPERTIES::LAUNCH_LAST_TRY => (new DateTime())->format('Y-m-d H:i:s')]); return $DBServer; } else { Logger::getLogger("SERVER_LAUNCH")->warn("{$pendingServers} servers in PENDING state on {$DBServer->platform}. Limit is: {$pendingServersLimit}. Launching server."); } } } try { $account = Scalr_Account::init()->loadById($DBServer->clientId); $account->validateLimit(Scalr_Limits::ACCOUNT_SERVERS, 1); PlatformFactory::NewPlatform($DBServer->platform)->LaunchServer($DBServer); $DBServer->status = SERVER_STATUS::PENDING; $DBServer->Save(); try { if ($reason) { list($reasonMsg, $reasonId) = is_array($reason) ? call_user_func_array($fnGetReason, $reason) : $fnGetReason($reason); } else { $reasonMsg = $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_REASON); $reasonId = $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_REASON_ID); } $DBServer->getServerHistory()->markAsLaunched($reasonMsg, $reasonId); $DBServer->updateTimelog('ts_launched'); if ($DBServer->imageId) { //Update Image last used date $image = Image::findOne([['id' => $DBServer->imageId], ['envId' => $DBServer->envId], ['platform' => $DBServer->platform], ['cloudLocation' => $DBServer->cloudLocation]]); if (!$image) { $image = Image::findOne([['id' => $DBServer->imageId], ['envId' => NULL], ['platform' => $DBServer->platform], ['cloudLocation' => $DBServer->cloudLocation]]); } if ($image) { $image->dtLastUsed = new DateTime(); $image->save(); } //Update Role last used date if ($DBServer->farmRoleId) { $dbRole = $DBServer->GetFarmRoleObject()->GetRoleObject(); $dbRole->dtLastUsed = date("Y-m-d H:i:s"); $dbRole->save(); } } } catch (Exception $e) { Logger::getLogger('SERVER_HISTORY')->error(sprintf("Cannot update servers history: {$e->getMessage()}")); } } catch (Exception $e) { Logger::getLogger(LOG_CATEGORY::FARM)->error(new FarmLogMessage($DBServer->farmId, sprintf("Cannot launch server on '%s' platform: %s", $DBServer->platform, $e->getMessage()), $DBServer->serverId)); $existingLaunchError = $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ERROR); $DBServer->status = SERVER_STATUS::PENDING_LAUNCH; $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_ERROR => $e->getMessage(), SERVER_PROPERTIES::LAUNCH_ATTEMPT => $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ATTEMPT) + 1, SERVER_PROPERTIES::LAUNCH_LAST_TRY => (new DateTime())->format('Y-m-d H:i:s')]); $DBServer->Save(); if ($DBServer->farmId && !$existingLaunchError) { Scalr::FireEvent($DBServer->farmId, new InstanceLaunchFailedEvent($DBServer, $e->getMessage())); } } if ($DBServer->status == SERVER_STATUS::PENDING) { Scalr::FireEvent($DBServer->farmId, new BeforeInstanceLaunchEvent($DBServer)); $DBServer->SetProperty(SERVER_PROPERTIES::LAUNCH_ERROR, ""); } return $DBServer; }
/** * @return Image */ public function getImageEntity() { return Image::findOne([['id' => $this->snapshotId], ['envId' => $this->envId], ['platform' => $this->platform], ['cloudLocation' => in_array($this->platform, [SERVER_PLATFORMS::GCE, SERVER_PLATFORMS::AZURE]) ? '' : $this->cloudLocation]]); }
/** * Add, replace or remove image in role * * @param string $platform The cloud platform * @param string $cloudLocation The cloud location * @param string $imageId optional Either Identifier of the Image to add or NULL to remove * @param integer $userId The identifier of the User who adds the Image * @param string $userEmail The email address of the User who adds the Image * * @throws ImageInUseException * @throws ImageNotFoundException * @throws NotAcceptableImageStatusException * @throws OsMismatchException * @throws \Scalr\Exception\ModelException */ public function setImage($platform, $cloudLocation, $imageId, $userId, $userEmail) { if (in_array($platform, [\SERVER_PLATFORMS::GCE, \SERVER_PLATFORMS::AZURE])) { $cloudLocation = ''; } $history = new ImageHistory(); $history->roleId = $this->id; $history->platform = $platform; $history->cloudLocation = $cloudLocation; $history->addedById = $userId; $history->addedByEmail = $userEmail; $oldImage = null; try { $oldImage = $this->getImage($platform, $cloudLocation); $history->oldImageId = $oldImage->imageId; if ($imageId) { if ($oldImage->imageId == $imageId) { return; } } } catch (\Exception $e) { } if ($imageId) { /* @var $newImage Image */ $newImage = Image::findOne([['id' => $imageId], ['platform' => $platform], ['cloudLocation' => $cloudLocation], ['$or' => [['accountId' => null], ['$and' => [['accountId' => $this->accountId], ['$or' => [['envId' => null], ['envId' => $this->envId]]]]]]]]); if (!$newImage) { throw new ImageNotFoundException(sprintf("The Image does not exist, or isn't owned by your account: %s, %s, %s", $platform, $cloudLocation, $imageId)); } if ($newImage->status !== Image::STATUS_ACTIVE) { throw new NotAcceptableImageStatusException(sprintf("You can't add image %s because of its status: %s", $newImage->id, $newImage->status)); } if ($newImage->getOs()->family && $newImage->getOs()->generation) { // check only if they are set if ($this->getOs()->family != $newImage->getOs()->family || $this->getOs()->generation != $newImage->getOs()->generation) { throw new OsMismatchException(sprintf("OS mismatch between Image: %s, family: %s and Role: %d, family: %s", $newImage->id, $newImage->getOs()->family, $this->id, $this->getOs()->family)); } } if ($this->isScalarized && !($newImage->isScalarized || $newImage->hasCloudInit)) { throw new ImageNotScalarizedException("You can not add the Image {$newImage->id} because neither it is not use Scalr Agent nor cloud-init"); } $history->imageId = $newImage->id; if ($oldImage) { $oldImage->delete(); } $newRoleImage = new RoleImage(); $newRoleImage->roleId = $this->id; $newRoleImage->imageId = $newImage->id; $newRoleImage->platform = $newImage->platform; $newRoleImage->cloudLocation = $newImage->cloudLocation; $newRoleImage->save(); } else { if ($oldImage) { if ($oldImage->isUsed()) { throw new ImageInUseException(sprintf("The Image for roleId: %d, platform: %s, cloudLocation: %s is used by some FarmRole", $oldImage->roleId, $oldImage->platform, $oldImage->cloudLocation)); } $oldImage->delete(); } } $history->save(); }
/** * @param JsonData $images * @param bool $removeFromCloud * @throws Scalr_Exception_Core * @throws \Scalr\Exception\ModelException */ public function xRemoveAction(JsonData $images, $removeFromCloud = false) { $this->request->restrictAccess(Acl::RESOURCE_FARMS_IMAGES, Acl::PERM_FARMS_IMAGES_MANAGE); $errors = []; $processed = []; $pending = []; foreach ($images as $i) { try { /* @var $im Image */ $im = Image::findOne([['id' => $i['id']], ['envId' => $this->getEnvironmentId(true)], ['platform' => $i['platform']], ['cloudLocation' => $i['cloudLocation']]]); if ($im) { if (!$im->getUsed()) { if ($removeFromCloud && $this->user->isUser()) { if ($im->isUsedGlobal()) { throw new Exception(sprintf("Unable to delete %s, this Image may be:\n- Still registered in another Environment or Account\n- Currently in-use by a Server in another Environment", $im->id)); } $im->status = Image::STATUS_DELETE; $im->save(); } else { if ($this->user->isScalrAdmin() && $im->isUsedGlobal()) { throw new Exception(sprintf("Unable to delete %s, this Image may be:\n- Still registered in another Environment or Account\n- Currently in-use by a Server in another Environment", $im->id)); } $im->delete(); $processed[] = $im->hash; } } } } catch (Exception $e) { $errors[] = $e->getMessage(); } } $this->response->data(['processed' => $processed, 'pending' => $pending]); if (count($errors)) { $this->response->warning("Images(s) successfully removed, but some errors occurred:\n" . implode("\n", $errors)); } else { $this->response->success('Images(s) successfully removed'); } }