/** * Generate conditions for sql query to limit access by only allowable farms. * Table `farms` should have alias `f`. * * @param string $permissionId optional * @return string */ public function getFarmSqlQuery($permissionId = null) { if (!$this->isAllowed(Acl::RESOURCE_FARMS, $permissionId)) { $q = []; if ($this->isAllowed(Acl::RESOURCE_TEAM_FARMS, $permissionId)) { $q[] = Farm::getUserTeamOwnershipSql($this->user->id); } if ($this->isAllowed(Acl::RESOURCE_OWN_FARMS, $permissionId)) { $q[] = "f.created_by_id = '{$this->user->getId()}'"; } if (count($q)) { $sql = '(' . join(' OR ', $q) . ')'; } else { $sql = '0'; // no permissions } } else { $sql = '1'; // all farms in env } return $sql; }
/** * @param int $farmId * @param int $expirePeriod * @param bool $manageable * @param string $owner * @param int $chefServerId * @param string $projectId * @param int $status * @throws Exception * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions */ public function xListFarmsAction($farmId = null, $expirePeriod = null, $manageable = false, $owner = null, $chefServerId = null, $projectId = null, $status = null) { $this->request->restrictAccess([Acl::RESOURCE_FARMS, Acl::RESOURCE_TEAM_FARMS, Acl::RESOURCE_OWN_FARMS]); $governance = new Scalr_Governance($this->getEnvironmentId()); $leaseStatus = $governance->isEnabled(Scalr_Governance::CATEGORY_GENERAL, Scalr_Governance::GENERAL_LEASE); $f = new Entity\Farm(); $sql = "\n SELECT {$f->fields('f')}, au.email AS ownerEmail,\n (SELECT " . Entity\Farm::getUserTeamOwnershipSql($this->getUser()->id) . ") AS farmTeamIdPerm,\n GROUP_CONCAT(DISTINCT at.name SEPARATOR ', ') AS farmTeams,\n GROUP_CONCAT(DISTINCT behavior) AS behaviors,\n (SELECT COUNT(*) FROM farm_roles WHERE farmid = f.id) AS rolesCnt,\n (SELECT COUNT(*) FROM dns_zones WHERE farm_id = f.id) AS zonesCnt,\n (SELECT COUNT(*) FROM server_alerts WHERE farm_id= f.id AND status = ?) AS alertsCnt,\n (SELECT COUNT(*) FROM servers WHERE farm_id = f.id AND status IN (?,?,?,?,?)) AS runningServers,\n (SELECT COUNT(*) FROM servers WHERE farm_id = f.id AND status IN (?,?)) AS suspendedServers,\n (SELECT COUNT(*) FROM servers WHERE farm_id = f.id AND status IN (?,?)) AS nonRunningServers\n FROM {$f->table('f')}\n LEFT JOIN account_users au ON au.id = f.created_by_id\n LEFT JOIN farm_teams ft ON ft.farm_id = {$f->columnId('f')}\n LEFT JOIN account_teams at ON at.id = ft.team_id\n LEFT JOIN farm_roles fr ON fr.farmid = {$f->columnId('f')}\n LEFT JOIN role_behaviors rb ON rb.role_id = fr.role_id\n WHERE {$f->columnEnvId('f')} = ?\n AND :FILTER:\n AND " . $this->request->getFarmSqlQuery($manageable ? Acl::PERM_FARMS_UPDATE : null); $args = [Entity\Server\Alert::STATUS_FAILED, Entity\Server::STATUS_PENDING, Entity\Server::STATUS_INIT, Entity\Server::STATUS_RUNNING, Entity\Server::STATUS_TEMPORARY, Entity\Server::STATUS_RESUMING, Entity\Server::STATUS_SUSPENDED, Entity\Server::STATUS_PENDING_SUSPEND, Entity\Server::STATUS_TERMINATED, Entity\Server::STATUS_PENDING_TERMINATE, $this->getEnvironmentId()]; if ($leaseStatus && $expirePeriod) { $dt = new DateTime(); $dt->add(new DateInterval('P' . $expirePeriod . 'D')); $sql .= " AND EXISTS (\n SELECT 1 FROM farm_settings\n WHERE farm_settings.farmid = f.id\n AND farm_settings.name = ?\n AND farm_settings.value != ''\n AND farm_settings.value < ?\n ) AND f.status = ?"; $args[] = Entity\FarmSetting::LEASE_TERMINATE_DATE; $args[] = $dt->format('Y-m-d H:i:s'); $args[] = Entity\Farm::STATUS_RUNNING; } if ($farmId) { $sql .= ' AND f.id = ?'; $args[] = $farmId; } if ($owner) { if ($owner == 'me') { $sql .= " AND {$f->columnOwnerId('f')} = ?"; $args[] = $this->getUser()->id; } else { if ($owner == 'team') { $sql .= " AND " . Entity\Farm::getUserTeamOwnershipSql($this->getUser()->id); } } } if ($chefServerId) { $sql .= " AND f.id IN (\n SELECT fr.farmid\n FROM farm_roles fr\n INNER JOIN farm_role_settings frs1 ON fr.id = frs1.farm_roleid AND frs1.name = ? AND frs1.value = ?\n INNER JOIN farm_role_settings frs2 ON fr.id = frs2.farm_roleid AND frs2.name = ? AND frs2.value = ?\n )"; $args[] = \Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID; $args[] = $chefServerId; $args[] = \Scalr_Role_Behavior_Chef::ROLE_CHEF_BOOTSTRAP; $args[] = 1; } if ($this->getContainer()->analytics->enabled && $projectId) { $sql .= " AND EXISTS (\n SELECT 1 FROM farm_settings\n WHERE farm_settings.farmid = f.id\n AND farm_settings.name = " . $this->db->qstr(Entity\FarmSetting::PROJECT_ID) . "\n AND farm_settings.value = ?) "; $args[] = $projectId; } $sql .= " GROUP BY {$f->columnId('f')}"; $response = $this->buildResponseFromSql2($sql, array('id', 'name', 'dtadded', 'ownerEmail', 'status'), array('f.name', 'f.id', 'f.comments'), $args); foreach ($response["data"] as &$r) { $farm = new Entity\Farm(); $farm->load($r); $row = get_object_vars($farm); $row['ownerEmail'] = $r['ownerEmail']; $row['farmTeams'] = $r['farmTeams']; $row['behaviors'] = $r['behaviors']; $row['rolesCnt'] = $r['rolesCnt']; $row['zonesCnt'] = $r['zonesCnt']; $row['alertsCnt'] = $r['alertsCnt']; $row['runningServers'] = $r['runningServers']; $row['suspendedServers'] = $r['suspendedServers']; $row['nonRunningServers'] = $r['nonRunningServers']; $row['added'] = Scalr_Util_DateTime::convertTz($farm->added); $row['lock'] = $farm->settings[Entity\FarmSetting::LOCK]; if ($row['lock']) { try { $farm->checkLocked(); } catch (\Scalr\Exception\LockedException $e) { $row['lockComment'] = $e->getMessage(); } } if ($leaseStatus && $farm->settings[Entity\FarmSetting::LEASE_STATUS]) { $row['lease'] = $farm->settings[Entity\FarmSetting::LEASE_NOTIFICATION_SEND] ? 'Expire' : $farm->settings[Entity\FarmSetting::LEASE_STATUS]; if ($row['lease'] == 'Expire') { $dt = new DateTime(); $td = new DateTime($farm->settings[Entity\FarmSetting::LEASE_TERMINATE_DATE]); $days = 0; $hours = 1; $interval = $dt->diff($td); if ($interval) { $days = $interval->days; $hours = $interval->h ? $interval->h : 1; } $row['leaseMessage'] = sprintf('Your farm lease is about to expire in %d %s, after which this farm will be terminated', $days ? $days : $hours, $days ? $days > 1 ? 'days' : 'day' : ($hours > 1 ? 'hours' : 'hour')); } } $behaviors = explode(',', $row['behaviors']); $row["havemysqlrole"] = in_array(ROLE_BEHAVIORS::MYSQL, $behaviors); $row["havemysql2role"] = in_array(ROLE_BEHAVIORS::MYSQL2, $behaviors); $row["havepgrole"] = in_array(ROLE_BEHAVIORS::POSTGRESQL, $behaviors); $row["haveredisrole"] = in_array(ROLE_BEHAVIORS::REDIS, $behaviors); $row["haverabbitmqrole"] = in_array(ROLE_BEHAVIORS::RABBITMQ, $behaviors); $row["havemongodbrole"] = in_array(ROLE_BEHAVIORS::MONGODB, $behaviors); $row["haveperconarole"] = in_array(ROLE_BEHAVIORS::PERCONA, $behaviors); $row["havemariadbrole"] = in_array(ROLE_BEHAVIORS::MARIADB, $behaviors); $row['statusTxt'] = Entity\Farm::getStatusName($farm->status); if ($row['status'] == Entity\Farm::STATUS_RUNNING) { $row['shortcuts'] = []; foreach (\Scalr\Model\Entity\ScriptShortcut::find([['farmId' => $farm->id], ['farmRoleId' => null]]) as $shortcut) { /* @var $shortcut \Scalr\Model\Entity\ScriptShortcut */ $row['shortcuts'][] = array('id' => $shortcut->id, 'name' => $shortcut->getScriptName()); } } $row['farmOwnerIdPerm'] = $farm->ownerId && $this->getUser()->id == $farm->ownerId; $row['farmTeamIdPerm'] = !!$r['farmTeamIdPerm']; $r = $row; } $this->response->data($response); }
/** * Get list of servers * * @param string $cloudServerId optional Cloud server ID * @param string $cloudServerLocation optional Cloud server location * @param string $hostname optional Hostname * @param int $farmId optional Farm ID * @param int $farmRoleId optional Farm role ID * @param int $roleId optional Role ID * @param string $serverId optional Server ID * @param string $imageId optional Image ID * @param boolean $showTerminated optional Whether to show terminated servers as well * @param string $uptime optional Uptime * @throws \Scalr_Exception_InsufficientPermissions */ public function xListServersAction($cloudServerId = null, $cloudServerLocation = null, $hostname = null, $farmId = null, $farmRoleId = null, $roleId = null, $serverId = null, $imageId = null, $showTerminated = null, $uptime = null) { if (!$this->request->isAllowed([Acl::RESOURCE_FARMS, Acl::RESOURCE_TEAM_FARMS, Acl::RESOURCE_OWN_FARMS]) && !$this->request->isAllowed(Acl::RESOURCE_IMAGES_ENVIRONMENT, Acl::PERM_IMAGES_ENVIRONMENT_MANAGE)) { throw new \Scalr_Exception_InsufficientPermissions(); } $sortParamsLoad = ''; foreach ($this->getSortOrder() as $param) { if ($param['property'] == 'remote_ip_int' || $param['property'] == 'local_ip_int') { $sortParamsLoad .= ", INET_ATON(servers." . substr($param['property'], 0, -4) . ") AS " . $param['property']; } } $stmFrom = "SELECT servers.*,\n f.name AS farm_name,\n roles.name AS role_name,\n roles.behaviors AS behaviors,\n farm_roles.alias AS role_alias,\n f.created_by_id AS farmOwnerId,\n (SELECT " . Entity\Farm::getUserTeamOwnershipSql($this->getUser()->id) . ") AS farmTeamIdPerm,\n servers.dtinitialized AS uptime,\n ste.last_error AS termination_error{$sortParamsLoad}\n FROM servers\n LEFT JOIN farms f ON servers.farm_id = f.id\n LEFT JOIN farm_roles ON farm_roles.id = servers.farm_roleid\n LEFT JOIN roles ON roles.id = farm_roles.role_id\n LEFT JOIN server_termination_errors ste ON servers.server_id = ste.server_id"; $stmWhere = ["servers.env_id = ?"]; $args = [$this->getEnvironmentId()]; $sqlFlt = []; if (!empty($cloudServerId)) { $cloudServerProps = [CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID, AZURE_SERVER_PROPERTIES::SERVER_NAME, EC2_SERVER_PROPERTIES::INSTANCE_ID, GCE_SERVER_PROPERTIES::SERVER_NAME, OPENSTACK_SERVER_PROPERTIES::SERVER_ID]; $sqlFlt["sp1"] = "sp1.`name` IN (" . implode(", ", array_fill(0, count($cloudServerProps), "?")) . ") AND sp1.`value` = ?"; foreach ($cloudServerProps as $spn) { $args[] = $spn; } $args[] = $cloudServerId; } if (!empty($cloudServerLocation)) { $cloudServerLocationProps = [CLOUDSTACK_SERVER_PROPERTIES::CLOUD_LOCATION, AZURE_SERVER_PROPERTIES::CLOUD_LOCATION, EC2_SERVER_PROPERTIES::REGION, GCE_SERVER_PROPERTIES::CLOUD_LOCATION, OPENSTACK_SERVER_PROPERTIES::CLOUD_LOCATION]; $sqlFlt["sp2"] = "sp2.`name` IN (" . implode(", ", array_fill(0, count($cloudServerLocationProps), "?")) . ") AND sp2.`value` = ?"; foreach ($cloudServerLocationProps as $spn) { $args[] = $spn; } $args[] = $cloudServerLocation; } if (!empty($hostname)) { $sqlFlt["sp3"] = "sp3.`name` = ? AND sp3.`value` LIKE ?"; $args[] = Scalr_Role_Behavior::SERVER_BASE_HOSTNAME; $args[] = "%" . $hostname . "%"; } if (!empty($sqlFlt)) { foreach ($sqlFlt as $alias => $where) { $stmFrom .= " INNER JOIN server_properties AS " . $alias . " ON servers.server_id = " . $alias . ".server_id"; $stmWhere[] = $where; } } if (!empty($farmId)) { $stmWhere[] = "farm_id = ?"; $args[] = $farmId; } $where = ["farm_id IS NOT NULL AND " . $this->request->getFarmSqlQuery()]; if ($this->request->isAllowed(Acl::RESOURCE_IMAGES_ENVIRONMENT, Acl::PERM_IMAGES_ENVIRONMENT_MANAGE)) { $where[] = "farm_id IS NULL AND servers.status IN (?, ?)"; $args[] = Entity\Server::STATUS_IMPORTING; $args[] = Entity\Server::STATUS_TEMPORARY; } $stmWhere[] = '(' . join(" OR ", $where) . ')'; if (!empty($farmRoleId)) { $stmWhere[] = "farm_roleid = ?"; $args[] = $farmRoleId; } if (!empty($roleId)) { $stmWhere[] = "farm_roles.role_id = ?"; $args[] = $roleId; } if (!empty($serverId)) { $stmWhere[] = "servers.server_id = ?"; $args[] = $serverId; } if (!empty($imageId)) { $stmWhere[] = "image_id = ?"; $args[] = $imageId; } if (empty($showTerminated)) { $stmWhere[] = "servers.status != ?"; $args[] = Entity\Server::STATUS_TERMINATED; } if (!empty($uptime) && preg_match('/^(m|l)([0-9]+)(d|h)$/', $uptime, $matches)) { if ($matches[1] == 'm') { $stmWhere[] = "servers.dtinitialized < ?"; } else { $stmWhere[] = "servers.dtinitialized > ?"; } $args[] = date("Y-m-d H:i:s", strtotime("-" . $matches[2] . ($matches[3] == 'd' ? 'day' : 'hour'))); } $stmWhere[] = ":FILTER:"; $response = $this->buildResponseFromSql2($stmFrom . " WHERE " . implode(" AND ", $stmWhere), ["platform", "farm_name", "role_name", "role_alias", "index", "servers.server_id", "remote_ip_int", "local_ip_int", "uptime", "status"], ["servers.server_id", "farm_id", "f.name", "remote_ip", "local_ip", "servers.status", "farm_roles.alias"], $args); $this->listServersResponseHelper($response); $this->response->data($response); }
/** * {@inheritdoc} * @see \Scalr\System\Zmq\Cron\TaskInterface::worker() */ public function worker($request) { $db = \Scalr::getDb(); //Warming up static DI cache \Scalr::getContainer()->warmup(); // Reconfigure observers \Scalr::ReconfigureObservers(); $bundleTask = BundleTask::LoadById($request->bundleTaskId); if (!$bundleTask instanceof BundleTask) { $this->getLogger()->fatal("Could not load bundle task id: %s", $request->bundleTaskId); return false; } else { $this->bundleTask = $bundleTask; $this->getLogger()->info("Processing bundle task id: %d status: %s serverid: %s", $bundleTask->id, $bundleTask->status, $bundleTask->serverId); } try { $dbServer = DBServer::LoadByID($bundleTask->serverId); } catch (\Scalr\Exception\ServerNotFoundException $e) { if (!$bundleTask->snapshotId && $bundleTask->bundleType != \SERVER_SNAPSHOT_CREATION_TYPE::GCE_WINDOWS) { $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::FAILED; $bundleTask->setDate('finished'); $bundleTask->failureReason = sprintf(_("Server '%s' was terminated during snapshot creation process"), $bundleTask->serverId); $bundleTask->Save(); return; } $this->getLogger()->warn("Could not load server: %s. %s says: %s", $bundleTask->serverId, get_class($e), $e->getMessage()); } catch (Exception $e) { $this->getLogger()->warn("Could not load server: %s. %s says: %s", $bundleTask->serverId, get_class($e), $e->getMessage()); } switch ($bundleTask->status) { case SERVER_SNAPSHOT_CREATION_STATUS::ESTABLISHING_COMMUNICATION: $conn = @fsockopen($dbServer->getSzrHost(), $dbServer->getPort(DBServer::PORT_CTRL), $errno, $errstr, 10); if ($conn) { $dbServer->SetProperty(SERVER_PROPERTIES::SZR_IMPORTING_OUT_CONNECTION, 1); $this->bundleTaskLog("Outbound connection successfully established. Awaiting user action: prebuild automation selection"); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::AWAITING_USER_ACTION; $this->bundleTaskLog(sprintf(_("Bundle task status: %s"), $bundleTask->status)); $bundleTask->Save(); } else { $errstr = sprintf("Unable to establish outbound (Scalr -> Scalarizr) communication (%s:%s): %s.", $dbServer->getSzrHost(), $dbServer->getPort(DBServer::PORT_CTRL), $errstr); $errMsg = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_OUT_CONNECTION_ERROR); if (!$errMsg || $errstr != $errMsg) { $dbServer->SetProperty(SERVER_PROPERTIES::SZR_IMPORTING_OUT_CONNECTION_ERROR, $errstr); $this->bundleTaskLog("{$errstr} Will try again in a few minutes."); } } return false; case SERVER_SNAPSHOT_CREATION_STATUS::AWAITING_USER_ACTION: //nothing to do; return false; case SERVER_SNAPSHOT_CREATION_STATUS::STARING_SERVER: $bundleTask->setDate('started'); case SERVER_SNAPSHOT_CREATION_STATUS::PREPARING_ENV: case SERVER_SNAPSHOT_CREATION_STATUS::INTALLING_SOFTWARE: if (!PlatformFactory::NewPlatform($dbServer->platform)->GetServerID($dbServer)) { $this->bundleTaskLog(sprintf(_("Waiting for temporary server"))); return false; } $status = PlatformFactory::NewPlatform($dbServer->platform)->GetServerRealStatus($dbServer); if ($status->isPending()) { //Server is in pensing state $this->bundleTaskLog(sprintf(_("Server status: %s"), $status->getName())); $this->bundleTaskLog(sprintf(_("Waiting for running state."), $status->getName())); return false; } elseif ($status->isTerminated()) { $this->bundleTaskLog(sprintf(_("Server status: %s"), $status->getName())); $dbServer->status = SERVER_STATUS::TERMINATED; $dbServer->save(); $bundleTask->SnapshotCreationFailed("Server was terminated and no longer available in cloud."); return false; } break; } $this->getLogger()->info("Continue bundle task id:%d status:%s", $bundleTask->id, $bundleTask->status); switch ($bundleTask->status) { case SERVER_SNAPSHOT_CREATION_STATUS::STARING_SERVER: $ips = PlatformFactory::NewPlatform($dbServer->platform)->GetServerIPAddresses($dbServer); $dbServer->remoteIp = $ips['remoteIp']; $dbServer->localIp = $ips['localIp']; $dbServer->save(); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::PREPARING_ENV; $bundleTask->save(); $this->bundleTaskLog(sprintf(_("Bundle task status: %s"), $bundleTask->status)); break; case SERVER_SNAPSHOT_CREATION_STATUS::PREPARING_ENV: $this->bundleTaskLog(sprintf(_("Initializing SSH2 session to the server"))); if ($dbServer->platform == SERVER_PLATFORMS::IDCF && !$dbServer->remoteIp) { try { $this->bundleTaskLog("Creating port forwarding rules to be able to connect to the server by SSH"); $environment = $dbServer->GetEnvironmentObject(); $cloudLocation = $dbServer->GetCloudLocation(); $platform = PlatformFactory::NewPlatform($dbServer->platform); $ccProps = $environment->keychain($dbServer->platform)->properties; $sharedIpId = $ccProps[CloudCredentialsProperty::CLOUDSTACK_SHARED_IP_ID . ".{$cloudLocation}"]; $sharedIp = $ccProps[CloudCredentialsProperty::CLOUDSTACK_SHARED_IP . ".{$cloudLocation}"]; $this->bundleTaskLog("Shared IP: {$sharedIp}"); $cs = $environment->cloudstack($dbServer->platform); // Create port forwarding rules for scalarizr $port = $ccProps[CloudCredentialsProperty::CLOUDSTACK_SZR_PORT_COUNTER . ".{$cloudLocation}.{$sharedIpId}"]; if (!$port) { $port1 = 30000; $port2 = 30001; $port3 = 30002; $port4 = 30003; } else { $port1 = $port + 1; $port2 = $port1 + 1; $port3 = $port2 + 1; $port4 = $port3 + 1; } $virtualmachineid = $dbServer->GetProperty(CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID); $result2 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8014, 'protocol' => "udp", 'publicport' => $port1, 'virtualmachineid' => $virtualmachineid)); $result1 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8013, 'protocol' => "tcp", 'publicport' => $port1, 'virtualmachineid' => $virtualmachineid)); $result3 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8010, 'protocol' => "tcp", 'publicport' => $port3, 'virtualmachineid' => $virtualmachineid)); $result4 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8008, 'protocol' => "tcp", 'publicport' => $port2, 'virtualmachineid' => $virtualmachineid)); $result5 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 22, 'protocol' => "tcp", 'publicport' => $port4, 'virtualmachineid' => $virtualmachineid)); $dbServer->SetProperties(array(SERVER_PROPERTIES::SZR_CTRL_PORT => $port1, SERVER_PROPERTIES::SZR_SNMP_PORT => $port1, SERVER_PROPERTIES::SZR_API_PORT => $port3, SERVER_PROPERTIES::SZR_UPDC_PORT => $port2, SERVER_PROPERTIES::CUSTOM_SSH_PORT => $port4)); $dbServer->remoteIp = $sharedIp; $dbServer->Save(); $ccProps->saveSettings([CloudCredentialsProperty::CLOUDSTACK_SZR_PORT_COUNTER . ".{$cloudLocation}.{$sharedIpId}" => $port4]); } catch (Exception $e) { $this->bundleTaskLog("Unable to create port-forwarding rules: {$e->getMessage()}"); } return false; } try { $ssh2Client = $dbServer->GetSsh2Client(); $ssh2Client->connect($dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH)); } catch (Exception $e) { $this->bundleTaskLog(sprintf(_("Scalr unable to establish SSH connection with server on %:%. Error: %s"), $dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH), $e->getMessage())); //TODO: Set status of bundle log to failed return false; } $this->bundleTaskLog(sprintf(_("Created SSH session. Username: %s"), $ssh2Client->getLogin())); //Prepare script $this->bundleTaskLog(sprintf(_("Uploading builder scripts..."))); $behaviors = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_BEHAVIOR); try { if ($dbServer->isOpenstack()) { $platform = SERVER_PLATFORMS::OPENSTACK; } else { $platform = $dbServer->platform; } $baseUrl = rtrim(\Scalr::config('scalr.endpoint.scheme') . "://" . \Scalr::config('scalr.endpoint.host'), '/'); $options = array('server-id' => $dbServer->serverId, 'role-name' => $bundleTask->roleName, 'crypto-key' => $dbServer->GetProperty(SERVER_PROPERTIES::SZR_KEY), 'platform' => $platform, 'queryenv-url' => $baseUrl . "/query-env", 'messaging-p2p.producer-url' => $baseUrl . "/messaging", 'behaviour' => trim(trim(str_replace("base", "", $behaviors), ",")), 'env-id' => $dbServer->envId, 'region' => $dbServer->GetCloudLocation(), 'scalr-id' => SCALR_ID); $command = 'scalarizr --import -y'; foreach ($options as $k => $v) { $command .= sprintf(' -o %s=%s', $k, $v); } if ($dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_MYSQL_SERVER_TYPE) == 'percona') { $recipes = 'mysql=percona'; } else { $recipes = ''; } $scalarizrBranch = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_DEV_SCALARIZR_BRANCH); $scriptContents = @file_get_contents(APPPATH . "/templates/services/role_builder/chef_import.tpl"); /* %CHEF_SERVER_URL% %CHEF_VALIDATOR_NAME% %CHEF_VALIDATOR_KEY% %CHEF_ENVIRONMENT% %CHEF_ROLE_NAME% */ $chefServerId = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_SERVER_ID); if ($chefServerId) { $chefServerInfo = $db->GetRow("SELECT * FROM services_chef_servers WHERE id=?", array($chefServerId)); $chefServerInfo['v_auth_key'] = \Scalr::getContainer()->crypto->decrypt($chefServerInfo['v_auth_key']); } $scriptContents = str_replace(array("%PLATFORM%", "%BEHAVIOURS%", "%SZR_IMPORT_STRING%", "%DEV%", "%SCALARIZR_BRANCH%", "%RECIPES%", "%BUILD_ONLY%", "%CHEF_SERVER_URL%", "%CHEF_VALIDATOR_NAME%", "%CHEF_VALIDATOR_KEY%", "%CHEF_ENVIRONMENT%", "%CHEF_ROLE%", "%CHEF_ROLE_NAME%", "%CHEF_NODE_NAME%", "\r\n"), array($platform, trim(str_replace("base", "", str_replace(",", " ", $behaviors))), $command, $scalarizrBranch ? '1' : '0', $scalarizrBranch, $recipes, '0', $chefServerInfo['url'], $chefServerInfo['v_username'], $chefServerInfo['v_auth_key'], $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_ENVIRONMENT), $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_ROLE_NAME), $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_ROLE_NAME), '', "\n"), $scriptContents); if (!$ssh2Client->sendFile('/tmp/scalr-builder.sh', $scriptContents, "w+", false)) { throw new Exception("Cannot upload script"); } /* $this->bundleTaskLog(sprintf(_("Uploading chef recipes..."))); if (!$ssh2Client->sendFile('/tmp/recipes.tar.gz', APPPATH . '/www/storage/chef/recipes.tar.gz')) { throw new Exception("Cannot upload chef recipes"); } */ } catch (Exception $e) { $this->bundleTaskLog(sprintf(_("Scripts upload failed: %s"), $e->getMessage())); //TODO: Set status of bundle log to failed return false; } $this->bundleTaskLog("Launching role builder routines on server"); $ssh2Client->exec("chmod 0777 /tmp/scalr-builder.sh"); // For CGE we need to use sudo if ($bundleTask->platform == SERVER_PLATFORMS::GCE || $bundleTask->osFamily == 'amazon') { $shell = $ssh2Client->getShell(); @stream_set_blocking($shell, true); @stream_set_timeout($shell, 5); @fwrite($shell, "sudo touch /var/log/role-builder-output.log 2>&1" . PHP_EOL); $output = @fgets($shell, 4096); $this->bundleTaskLog("Verbose 1: {$output}"); @fwrite($shell, "sudo chmod 0666 /var/log/role-builder-output.log 2>&1" . PHP_EOL); $output2 = @fgets($shell, 4096); $this->bundleTaskLog("Verbose 2: {$output2}"); @fwrite($shell, "sudo setsid /tmp/scalr-builder.sh > /var/log/role-builder-output.log 2>&1 &" . PHP_EOL); $output3 = @fgets($shell, 4096); $this->bundleTaskLog("Verbose 3: {$output3}"); sleep(5); $meta = stream_get_meta_data($shell); $this->bundleTaskLog(sprintf("Verbose (Meta): %s", json_encode($meta))); $i = 4; if ($meta['eof'] == false && $meta['unread_bytes'] != 0) { $output4 = @fread($shell, $meta['unread_bytes']); $this->bundleTaskLog("Verbose {$i}: {$output4}"); $meta = stream_get_meta_data($shell); $this->bundleTaskLog(sprintf("Verbose (Meta): %s", json_encode($meta))); } @fclose($shell); /* $r1 = $ssh2Client->exec("sudo touch /var/log/role-builder-output.log"); $this->bundleTaskLog("1: {$r1} ({$ssh2Client->stdErr})"); $r2 = $ssh2Client->exec("sudo chmod 0666 /var/log/role-builder-output.log"); $this->bundleTaskLog("2: {$r2} ({$ssh2Client->stdErr})"); $r3 = $ssh2Client->exec("sudo setsid /tmp/scalr-builder.sh > /var/log/role-builder-output.log 2>&1 &"); $this->bundleTaskLog("3: {$r3} ({$ssh2Client->stdErr})"); */ } else { $ssh2Client->exec("setsid /tmp/scalr-builder.sh > /var/log/role-builder-output.log 2>&1 &"); } $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::INTALLING_SOFTWARE; $bundleTask->save(); break; case SERVER_SNAPSHOT_CREATION_STATUS::INTALLING_SOFTWARE: try { $ssh2Client = $dbServer->GetSsh2Client(); $ssh2Client->connect($dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH)); } catch (Exception $e) { $this->bundleTaskLog(sprintf(_("Scalr unable to establish SSH connection with server on %:%. Error: %s"), $dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH), $e->getMessage())); //TODO: Set status of bundle log to failed return false; } $log = $ssh2Client->getFile('/var/log/role-builder-output.log'); $log_lines = explode("\r\n", $log); $last_msg = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_LAST_LOG_MESSAGE); while ($msg = trim(array_shift($log_lines))) { if (substr($msg, -1, 1) != ']') { continue; } if ($last_msg) { if ($msg != $last_msg) { continue; } elseif ($msg == $last_msg) { $last_msg = null; continue; } } if (stristr($msg, '[ Failed ]')) { $stepLog = $ssh2Client->getFile('/var/log/role-builder-step.log'); $this->bundleTaskLog(sprintf("role-builder-step.log: %s", $stepLog)); $bundleTask->SnapshotCreationFailed($msg); } else { $this->bundleTaskLog($msg); $dbServer->SetProperty(SERVER_PROPERTIES::SZR_IMPORTING_LAST_LOG_MESSAGE, $msg); } } //Read /var/log/role-builder-output.log break; case SERVER_SNAPSHOT_CREATION_STATUS::PENDING: try { $platformModule = PlatformFactory::NewPlatform($bundleTask->platform); $platformModule->CreateServerSnapshot($bundleTask); } catch (Exception $e) { $this->getLogger()->error($e->getMessage()); $bundleTask->SnapshotCreationFailed($e->getMessage()); } break; case SERVER_SNAPSHOT_CREATION_STATUS::PREPARING: $addedTime = strtotime($bundleTask->dateAdded); if ($addedTime + 3600 < time()) { $bundleTask->SnapshotCreationFailed("Server didn't send PrepareBundleResult message in time."); } break; case SERVER_SNAPSHOT_CREATION_STATUS::IN_PROGRESS: PlatformFactory::NewPlatform($bundleTask->platform)->CheckServerSnapshotStatus($bundleTask); break; case SERVER_SNAPSHOT_CREATION_STATUS::CREATING_ROLE: try { if ($bundleTask->object == BundleTask::BUNDLETASK_OBJECT_IMAGE) { if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { $dbRole = $dbServer->GetFarmRoleObject()->GetRoleObject(); $dbRole->__getNewRoleObject()->setImage($bundleTask->platform, $bundleTask->cloudLocation, $bundleTask->snapshotId, $bundleTask->createdById, $bundleTask->createdByEmail); $this->bundleTaskLog(sprintf(_("Image replacement completed."))); } $this->bundleTaskLog(sprintf(_("Bundle task completed."))); $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; $bundleTask->Save(); } elseif ($bundleTask->object == BundleTask::BUNDLETASK_OBJECT_ROLE) { if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { $saveOldRole = false; try { $dbRole = $dbServer->GetFarmRoleObject()->GetRoleObject(); if ($dbRole->name == $bundleTask->roleName && $dbRole->envId == $bundleTask->envId) { $saveOldRole = true; } } catch (Exception $e) { //NO OLD ROLE } if ($dbRole && $saveOldRole) { if ($dbServer) { $new_role_name = BundleTask::GenerateRoleName($dbServer->GetFarmRoleObject(), $dbServer); } else { $new_role_name = $bundleTask->roleName . "-" . rand(1000, 9999); } $dbRole->name = $new_role_name; $this->bundleTaskLog(sprintf(_("Old role '%s' (ID: %s) renamed to '%s'"), $bundleTask->roleName, $dbRole->id, $new_role_name)); $dbRole->save(); } } try { $DBRole = DBRole::createFromBundleTask($bundleTask); } catch (Exception $e) { $bundleTask->SnapshotCreationFailed("Role creation failed due to internal error ({$e->getMessage()}). Please try again."); return; } if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::NO_REPLACE) { $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; $this->bundleTaskLog(sprintf(_("Replacement type: %s. Bundle task status: %s"), SERVER_REPLACEMENT_TYPE::NO_REPLACE, SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS)); } else { try { $this->bundleTaskLog(sprintf(_("Replacement type: %s"), $bundleTask->replaceType)); $r_farm_roles = array(); try { $DBFarm = DBFarm::LoadByID($bundleTask->farmId); } catch (Exception $e) { if (stristr($e->getMessage(), "not found in database")) { $bundleTask->SnapshotCreationFailed("Farm was removed before task was finished"); } return; } if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_FARM) { try { $r_farm_roles[] = $DBFarm->GetFarmRoleByRoleID($bundleTask->prototypeRoleId); } catch (Exception $e) { } } elseif ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { /* @var $user Entity\Account\User */ $user = Entity\Account\User::findPk($bundleTask->createdById); /* @var $env Entity\Account\Environment */ $env = Entity\Account\Environment::findPk($bundleTask->envId); /* @var $acl Acl */ $acl = Scalr::getContainer()->acl; $sql = "SELECT fr.id FROM farm_roles fr JOIN farms f ON f.id = fr.farmid WHERE fr.role_id=? AND f.env_id = ?"; $args = [$bundleTask->prototypeRoleId, $bundleTask->envId]; if (!$acl->isUserAllowedByEnvironment($user, $env, Acl::RESOURCE_FARMS, Acl::PERM_FARMS_UPDATE)) { $q = []; if ($acl->isUserAllowedByEnvironment($user, $env, Acl::RESOURCE_TEAM_FARMS, Acl::PERM_FARMS_UPDATE)) { $q[] = Entity\Farm::getUserTeamOwnershipSql($user->id); } if ($acl->isUserAllowedByEnvironment($user, $env, Acl::RESOURCE_OWN_FARMS, Acl::PERM_FARMS_UPDATE)) { $q[] = "f.created_by_id = ?"; $args[] = $user->getId(); } if (count($q)) { $sql .= ' AND (' . join(' OR ', $q) . ')'; } else { $sql .= ' AND 0'; // no permissions } } $farm_roles = $db->GetAll($sql, $args); foreach ($farm_roles as $farm_role) { try { $r_farm_roles[] = DBFarmRole::LoadByID($farm_role['id']); } catch (Exception $e) { } } } foreach ($r_farm_roles as $DBFarmRole) { if ($DBFarmRole->CloudLocation != $bundleTask->cloudLocation) { $this->bundleTaskLog(sprintf("Role '%s' (ID: %s), farm '%s' (ID: %s) using the same role " . "but in abother cloud location. Skiping it.", $DBFarmRole->GetRoleObject()->name, $DBFarmRole->ID, $DBFarmRole->GetFarmObject()->Name, $DBFarmRole->FarmID)); } else { $DBFarmRole->RoleID = $bundleTask->roleId; $DBFarmRole->Save(); } } $this->bundleTaskLog(sprintf(_("Replacement completed. Bundle task completed."))); try { if ($dbServer->status == SERVER_STATUS::IMPORTING) { $dbServer->Remove(); } elseif ($dbServer->status == SERVER_STATUS::TEMPORARY) { $this->bundleTaskLog("Terminating temporary server"); $dbServer->terminate(DBServer::TERMINATE_REASON_TEMPORARY_SERVER_ROLE_BUILDER); $this->bundleTaskLog("Termination request has been sent"); } } catch (Exception $e) { $this->bundleTaskLog("Warning: {$e->getMessage()}"); } $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; $bundleTask->Save(); } catch (Exception $e) { $this->getLogger()->error($e->getMessage()); $this->bundleTaskLog(sprintf(_("Server replacement failed: %s"), $e->getMessage())); $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; } } } if ($bundleTask->status == SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS) { try { if ($dbServer->status == SERVER_STATUS::IMPORTING) { $dbServer->Remove(); } elseif ($dbServer->status == SERVER_STATUS::TEMPORARY) { $this->bundleTaskLog("Terminating temporary server"); $dbServer->terminate(DBServer::TERMINATE_REASON_TEMPORARY_SERVER_ROLE_BUILDER); $this->bundleTaskLog("Termination request has been sent"); } } catch (Exception $e) { $this->bundleTaskLog("Warning: {$e->getMessage()}"); } } $bundleTask->Save(); } catch (Exception $e) { $this->getLogger()->error($e->getMessage()); } break; } return $request; }
/** * @param string $query * @throws Scalr_Exception_Core */ public function xSearchResourcesAction($query) { if (trim($query) == '') { $this->response->data(['data' => []]); return; } $environments = $this->request->getScope() == ScopeInterface::SCOPE_ACCOUNT ? array_map(function ($r) { return $r['id']; }, $this->user->getEnvironments()) : [$this->getEnvironmentId()]; $f = new Entity\Farm(); $s = new Entity\Server(); $fr = new Entity\FarmRole(); $ft = new Entity\FarmTeam(); $e = new Entity\Account\Environment(); $at = new Entity\Account\Team(); $sp = new Entity\Server\Property(); $farmSql = []; $serverSql = []; $queryEnc = "%{$query}%"; foreach ($environments as $envId) { $acl = $this->user->getAclRolesByEnvironment($envId); $isTermporaryServerPerm = $acl->isAllowed(Acl::RESOURCE_IMAGES_ENVIRONMENT, Acl::PERM_IMAGES_ENVIRONMENT_BUILD) || $acl->isAllowed(Acl::RESOURCE_IMAGES_ENVIRONMENT, Acl::PERM_IMAGES_ENVIRONMENT_IMPORT); if ($acl->isAllowed(Acl::RESOURCE_FARMS)) { $farmSql[] = "{$f->columnEnvId('f')} = {$envId}"; if ($isTermporaryServerPerm) { $serverSql[] = "{$s->columnEnvId} = {$envId}"; } else { $serverSql[] = "{$s->columnEnvId} = {$envId} AND {$s->columnFarmId} IS NOT NULL"; } } else { $q = []; if ($acl->isAllowed(Acl::RESOURCE_TEAM_FARMS)) { $q[] = Entity\Farm::getUserTeamOwnershipSql($this->getUser()->id); } if ($acl->isAllowed(Acl::RESOURCE_OWN_FARMS)) { $q[] = "{$f->columnOwnerId('f')} = '" . intval($this->getUser()->id) . "'"; } if (count($q)) { $farmSql[] = "{$f->columnEnvId('f')} = {$envId} AND (" . join(" OR ", $q) . ")"; } if ($isTermporaryServerPerm) { $q[] = "{$s->columnStatus} IN ('" . Entity\Server::STATUS_IMPORTING . "', '" . Entity\Server::STATUS_TEMPORARY . "') AND {$s->columnFarmId} IS NULL"; } if (count($q)) { $serverSql[] = "{$s->columnEnvId} = {$envId} AND (" . join(" OR ", $q) . ")"; } } } $farms = []; if (count($farmSql)) { $farmStmt = $this->db->Execute("\n SELECT {$f->columnId('f')} AS id, {$f->columnName('f')} AS name, {$f->columnEnvId('f')} AS envId, {$f->columnStatus('f')} AS status,\n {$f->columnAdded('f')} AS added, {$f->columnCreatedByEmail('f')} AS createdByEmail, {$e->columnName} AS `envName`,\n GROUP_CONCAT({$at->columnName} SEPARATOR ', ') AS teamName\n FROM {$f->table('f')}\n LEFT JOIN {$e->table()} ON {$f->columnEnvId('f')} = {$e->columnId}\n LEFT JOIN {$ft->table()} ON {$ft->columnFarmId} = {$f->columnId('f')}\n LEFT JOIN {$at->table()} ON {$at->columnId} = {$ft->columnTeamId}\n WHERE ({$f->columnName('f')} LIKE ? OR {$f->columnId('f')} = ?) AND (" . join(" OR ", $farmSql) . ")\n GROUP BY {$f->columnId('f')}", [$queryEnc, $query]); $names = ['id' => 'ID', 'name' => 'Name']; while ($farm = $farmStmt->FetchRow()) { $farm['status'] = Entity\Farm::getStatusName($farm['status']); $farm['added'] = Scalr_Util_DateTime::convertTz($farm['added'], 'M j, Y H:i'); if (stristr($farm['name'], $query)) { $m = 'name'; } else { $m = 'id'; } $farms[] = ['entityName' => 'farm', 'envId' => $farm['envId'], 'envName' => $farm['envName'], 'matchField' => $names[$m], 'matchValue' => $farm[$m], 'data' => $farm]; } } $servers = []; if (count($serverSql)) { $serverStmt = $this->db->Execute("\n SELECT {$s->columnServerId} AS serverId, {$s->columnFarmId} AS farmId, {$s->columnFarmRoleId} AS farmRoleId,\n {$s->columnEnvId} AS envId, {$s->columnPlatform} AS platform, {$s->columnInstanceTypeName} AS instanceTypeName,\n {$s->columnStatus} AS status, {$s->columnCloudLocation} AS cloudLocation, {$s->columnRemoteIp} AS publicIp,\n {$s->columnLocalIp} AS privateIp, {$s->columnAdded} AS added, {$f->columnName('f')} AS farmName,\n {$fr->columnAlias} AS farmRoleName, {$e->columnName} AS `envName`, {$fr->columnRoleId} AS roleId,\n {$sp->columnValue('sp1', 'hostname')}\n FROM {$s->table()}\n LEFT JOIN {$f->table('f')} ON {$f->columnId('f')} = {$s->columnFarmId}\n LEFT JOIN {$fr->table()} ON {$fr->columnId} = {$s->columnFarmRoleId}\n LEFT JOIN {$e->table()} ON {$e->columnId} = {$s->columnEnvId}\n LEFT JOIN {$sp->table('sp1')} ON {$sp->columnServerId('sp1')} = {$s->columnServerId} AND {$sp->columnName('sp1')} = ?\n WHERE ({$s->columnRemoteIp} LIKE ? OR {$s->columnLocalIp} LIKE ? OR {$sp->columnValue('sp1')} LIKE ?) AND (" . join(" OR ", $serverSql) . ")\n GROUP BY {$s->columnServerId}", [Scalr_Role_Behavior::SERVER_BASE_HOSTNAME, $queryEnc, $queryEnc, $queryEnc]); $names = ['publicIp' => 'Public IP', 'privateIp' => 'Private IP', 'hostname' => 'Hostname']; while ($server = $serverStmt->FetchRow()) { $server['added'] = Scalr_Util_DateTime::convertTz($server['added'], 'M j, Y H:i'); if (strstr($server['publicIp'], $query)) { $m = 'publicIp'; } else { if (strstr($server['privateIp'], $query)) { $m = 'privateIp'; } else { $m = 'hostname'; } } $servers[] = ['entityName' => 'server', 'envId' => $server['envId'], 'envName' => $server['envName'], 'matchField' => $names[$m], 'matchValue' => $server[$m], 'data' => $server]; } } $this->response->data(['data' => array_merge($farms, $servers)]); }