Skip to content

Commit cff9166

Browse files
committed
Stop the user in case they add resources that exceed their limit
Since the current API does not provide a way to stop an update, this might lead in a state where the environment is not working and even doing forks will initialize new environment in this broken state. This PR tries to calculate if the requested update will exceed the current user limit and if it does, it stops the operation. In case the user wants to proceed, they can use the `--force` argument.
1 parent c04a058 commit cff9166

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

src/Command/Resources/ResourcesSetCommand.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ protected function configure()
3535
'Set the disk size (in MB) of apps or services.'
3636
. "\nItems are in the format <info>name:value</info> as above."
3737
)
38+
->addOption('force', 'f', InputOption::VALUE_NONE, 'Try to run the update, even if it might exceed your limits')
3839
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Show the changes that would be made, without changing anything')
3940
->addProjectOption()
4041
->addEnvironmentOption()
@@ -134,11 +135,16 @@ protected function execute(InputInterface $input, OutputInterface $output)
134135
&& $input->getOption('disk') === [];
135136

136137
$updates = [];
138+
$current = [];
137139
foreach ($services as $name => $service) {
138140
$type = $this->typeName($service);
139141
$group = $this->group($service);
140142

141143
$properties = $service->getProperties();
144+
$current[$group][$name]['resources']['profile_size'] = $properties['resources']['profile_size'];
145+
$current[$group][$name]['instance_count'] = $properties['instance_count'];
146+
$current[$group][$name]['disk'] = $properties['disk'];
147+
$current[$group][$name]['sizes'] = $containerProfiles[$properties['container_profile']];
142148

143149
$header = '<options=bold>' . ucfirst($type) . ': </><options=bold,underscore>' . $name . '</>';
144150
$headerShown = false;
@@ -259,6 +265,49 @@ protected function execute(InputInterface $input, OutputInterface $output)
259265

260266
$this->debug('Raw updates: ' . json_encode($updates, JSON_UNESCAPED_SLASHES));
261267

268+
$project = $this->getSelectedProject();
269+
$organization = $this->api()->getClient()->getOrganizationById($project->getProperty('organization'));
270+
$profile = $organization->getProfile();
271+
if ($input->getOption('force') === false && isset($profile->resources_limit) && $profile->resources_limit) {
272+
$diff = $this->computeMemoryCPUStorageDiff($updates, $current);
273+
$limit = $profile->resources_limit['limit'];
274+
$used = $profile->resources_limit['used']['totals'];
275+
276+
$this->debug('Raw diff: ' . json_encode($diff, JSON_UNESCAPED_SLASHES));
277+
$this->debug('Raw limits: ' . json_encode($limit, JSON_UNESCAPED_SLASHES));
278+
$this->debug('Raw used: ' . json_encode($used, JSON_UNESCAPED_SLASHES));
279+
280+
$errored = false;
281+
if ($limit['cpu'] < $used['cpu'] + $diff['cpu']) {
282+
$this->stdErr->writeln(sprintf(
283+
'The requested resources will exceed your organization\'s trial CPU limit, which is: <comment>%s</comment>.',
284+
$limit['cpu'],
285+
));
286+
$errored = true;
287+
}
288+
289+
if ($limit['memory'] < $used['memory'] + ($diff['memory'] / 1024)) {
290+
$this->stdErr->writeln(sprintf(
291+
'The requested resources will exceed your organization\'s trial memory limit, which is: <comment>%sGB</comment>.',
292+
$limit['memory'],
293+
));
294+
$errored = true;
295+
}
296+
297+
if ($limit['storage'] < $used['storage'] + ($diff['disk'] / 1024)) {
298+
$this->stdErr->writeln(sprintf(
299+
'The requested resources will exceed your organization\'s trial storage limit, which is: <comment>%sGB</comment>.',
300+
$limit['storage'],
301+
));
302+
$errored = true;
303+
}
304+
305+
if ($errored) {
306+
$this->stdErr->writeln('Please adjust your resources or activate your subscription.');
307+
return 1;
308+
}
309+
}
310+
262311
if ($input->getOption('dry-run')) {
263312
return 0;
264313
}
@@ -581,4 +630,65 @@ private function formatErrors(array $errors, $optionName)
581630
}
582631
return $ret;
583632
}
633+
634+
/**
635+
* Compute the total memory/CPU/storage diff that will occur when the given update
636+
* is applied.
637+
*
638+
* @param array $updates
639+
* @param array $current
640+
*
641+
* @return array
642+
*/
643+
private function computeMemoryCPUStorageDiff(array $updates, array $current)
644+
{
645+
$diff = [
646+
'memory' => 0,
647+
'cpu' => 0,
648+
'disk' => 0,
649+
];
650+
foreach ($updates as $group => $groupUpdates) {
651+
foreach ($groupUpdates as $serviceName => $serviceUpdates) {
652+
if (isset($current[$group][$serviceName]['instance_count']) === false) {
653+
$current[$group][$serviceName]['instance_count'] = 1;
654+
}
655+
if (isset($current[$group][$serviceName]['disk']) === false) {
656+
$current[$group][$serviceName]['disk'] = 0;
657+
}
658+
659+
$currentCount = $current[$group][$serviceName]['instance_count'];
660+
$currentSize = $current[$group][$serviceName]['resources']['profile_size'];
661+
$currentStorage = $current[$group][$serviceName]['disk'];
662+
663+
$newCount = $currentCount;
664+
$newSize = $currentSize;
665+
$newStorage = $currentStorage;
666+
if (isset($serviceUpdates['instance_count'])) {
667+
$newCount = $serviceUpdates['instance_count'];
668+
}
669+
if (isset($serviceUpdates['resources'])) {
670+
$newSize = $serviceUpdates['resources']['profile_size'];
671+
}
672+
if (isset($serviceUpdates['disk'])) {
673+
$newStorage = $serviceUpdates['disk'];
674+
}
675+
676+
$currentService = $current[$group][$serviceName];
677+
$currentSize = $currentService['resources']['profile_size'];
678+
$currentProfile = $currentService['sizes'][$currentSize];
679+
$currentCPU = $currentCount * $currentProfile['cpu'];
680+
$currentRAM = $currentCount * $currentProfile['memory'];
681+
682+
$newProfile = $currentService['sizes'][$newSize];
683+
$newCPU = $newCount * $newProfile['cpu'];
684+
$newRAM = $newCount * $newProfile['memory'];
685+
686+
$diff['memory'] += $newRAM - $currentRAM;
687+
$diff['cpu'] += $newCPU - $currentCPU;
688+
$diff['disk'] += $newStorage - $currentStorage;
689+
}
690+
}
691+
692+
return $diff;
693+
}
584694
}

0 commit comments

Comments
 (0)