/**
  * @test
  */
 public function getUnsresolvedParameter()
 {
     $blueprint = $this->getMockedBlueprint(['parameters' => ['Foo' => '{env:DONTRESOVLE}']]);
     $parameters = $blueprint->getParameters(false);
     $parameters = Div::flatten($parameters, 'ParameterKey', 'ParameterValue');
     $this->assertEquals('{env:DONTRESOVLE}', $parameters['Foo']);
 }
 /**
  * @param \StackFormation\Template[] $templates
  * @param string|null                $description
  * @param array                      $additionalData
  *
  * @return string
  * @throws \Exception
  */
 public function merge(array $templates, $description = null, array $additionalData = [])
 {
     if (count($templates) == 0) {
         throw new \InvalidArgumentException('No templates given');
     }
     $mergedTemplate = ['AWSTemplateFormatVersion' => '2010-09-09'];
     $mergeKeys = ['Parameters', 'Mappings', 'Conditions', 'Resources', 'Outputs', 'Metadata'];
     foreach ($templates as $template) {
         if (!$template instanceof \StackFormation\Template) {
             throw new \InvalidArgumentException('Expecting an array of \\StackFormation\\Template objects');
         }
         try {
             $array = $template->getDecodedJson();
             // Copy the current description into the final template
             if (!empty($array['Description'])) {
                 $mergedTemplate['Description'] = $array['Description'];
             }
             // Merge keys from current template with final template
             foreach ($mergeKeys as $mergeKey) {
                 if (isset($array[$mergeKey]) && is_array($array[$mergeKey])) {
                     foreach ($array[$mergeKey] as $key => $value) {
                         if (isset($mergedTemplate[$mergeKey][$key])) {
                             // it's ok if the parameter has the same name and type...
                             if ($mergeKey != 'Parameters' || $value['Type'] != $mergedTemplate[$mergeKey][$key]['Type']) {
                                 throw new \Exception("Duplicate key '{$key}' found in '{$mergeKey}'");
                             }
                         }
                         $mergedTemplate[$mergeKey][$key] = $value;
                     }
                 }
             }
         } catch (TemplateDecodeException $e) {
             if (Div::isProgramInstalled('jq')) {
                 $tmpfile = tempnam(sys_get_temp_dir(), 'json_validate_');
                 file_put_contents($tmpfile, $template->getProcessedTemplate());
                 passthru('jq . ' . $tmpfile);
                 unlink($tmpfile);
             }
             throw $e;
         }
     }
     // If a description override is specified use it
     if (!empty($description)) {
         $mergedTemplate['Description'] = trim($description);
     }
     if (empty($mergedTemplate['Description'])) {
         $mergedTemplate['Description'] = 'Merged Template';
     }
     $mergedTemplate = array_merge_recursive($mergedTemplate, $additionalData);
     $json = json_encode($mergedTemplate, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
     // Check for max template size
     if (strlen($json) > self::MAX_CF_TEMPLATE_SIZE) {
         $json = json_encode($mergedTemplate, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
         // Re-check for max template size
         if (strlen($json) > self::MAX_CF_TEMPLATE_SIZE) {
             throw new \Exception(sprintf('Template too big (%s bytes). Maximum template size is %s bytes.', strlen($json), self::MAX_CF_TEMPLATE_SIZE));
         }
     }
     return $json;
 }
Esempio n. 3
0
 public function compare()
 {
     if (empty($this->stack)) {
         throw new \InvalidArgumentException('Stack not set');
     }
     if (empty($this->blueprint)) {
         throw new \InvalidArgumentException('Blueprint not set');
     }
     $tmp = [];
     try {
         // parameters
         if ($this->output->isVerbose()) {
             $this->output->writeln($this->stack->getName() . ': Comparing parameters');
         }
         $parametersStack = $this->stack->getParameters();
         $parametersBlueprint = $this->blueprint->getParameters(true);
         $parametersBlueprint = Div::flatten($parametersBlueprint, 'ParameterKey', 'ParameterValue');
         if ($this->parametersAreEqual($parametersStack, $parametersBlueprint)) {
             $tmp['parameters'] = "<fg=green>equal</>";
         } else {
             $tmp['parameters'] = "<fg=red>different</>";
             $tmp['error'] = true;
         }
         // template
         if ($this->output->isVerbose()) {
             $this->output->writeln($this->stack->getName() . ': Comparing template');
         }
         $templateStack = trim($this->stack->getTemplate());
         $templateBlueprint = trim($this->blueprint->getPreprocessedTemplate());
         $templateStack = $this->normalizeJson($templateStack);
         $templateBlueprint = $this->normalizeJson($templateBlueprint);
         if ($templateStack === $templateBlueprint) {
             $tmp['template'] = "<fg=green>equal</>";
         } else {
             $tmp['template'] = "<fg=red>different</>";
             $tmp['error'] = true;
         }
     } catch (CloudFormationException $e) {
         $tmp['parameters'] = 'Stack not found';
         $tmp['template'] = 'Stack not found';
         $tmp['error'] = true;
     } catch (\Exception $e) {
         $tmp['parameters'] = '<fg=red>EXCEPTION: ' . $e->getMessage() . '</>';
         $tmp['template'] = 'EXCEPTION';
         $tmp['error'] = true;
     }
     return $tmp;
 }
 protected function interactAskForBlueprint(InputInterface $input, OutputInterface $output)
 {
     $blueprint = $input->getArgument('blueprint');
     if (empty($blueprint) || strpos($blueprint, '*') !== false || strpos($blueprint, '?') !== false) {
         $choices = $this->blueprintFactory->getBlueprintLabels($blueprint ? $blueprint : null);
         if (count($choices) == 0) {
             throw new \Exception('No matching blueprints found');
         } elseif (count($choices) == 1) {
             $blueprint = end($choices);
         } else {
             $helper = $this->getHelper('question');
             $question = new ChoiceQuestion('Please select a blueprint', $choices);
             $question->setErrorMessage('Blueprint %s is invalid.');
             $blueprint = $helper->ask($input, $output, $question);
         }
         $output->writeln('Selected blueprint: ' . $blueprint);
         list($blueprint) = explode(' ', $blueprint);
     } elseif (!empty($blueprint) && !$this->blueprintFactory->blueprintExists($blueprint)) {
         if ($result = $this->blueprintFactory->findByStackname($blueprint)) {
             $output->writeln('Blueprint reverse match found: <fg=green>' . $result['blueprint'] . '</>');
             $output->writeln('With ENV vars: <fg=green>' . Helper\Div::assocArrayToString($result['envvars']) . '</>');
             $helper = $this->getHelper('question');
             $question = new ConfirmationQuestion("Use this blueprint and set env vars? [y/N] ", false);
             if (!$helper->ask($input, $output, $question)) {
                 throw new \Exception('Operation aborted');
             }
             $blueprint = $result['blueprint'];
             foreach ($result['envvars'] as $var => $value) {
                 $output->writeln("Setting env var: {$var}={$value}");
                 putenv("{$var}={$value}");
             }
         }
     }
     $input->setArgument('blueprint', $blueprint);
     return $blueprint;
 }
Esempio n. 5
0
 /**
  * Get outputs
  *
  * @return array
  */
 public function getOutputs()
 {
     if (!isset($this->data['Outputs'])) {
         return [];
     }
     return Div::flatten($this->data['Outputs'], 'OutputKey', 'OutputValue');
 }
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $nameFilter = $input->getOption('nameFilter');
     $stacks = $this->getStackFactory()->getStacksFromApi(false, $nameFilter);
     $error = false;
     $data = [];
     foreach ($stacks as $stackName => $stack) {
         /* @var $stack Stack */
         $this->dependencyTracker->reset();
         $tmp = [];
         $tmp['stackName'] = $stackName;
         $tmp['status'] = Helper\Decorator::decorateStatus($stack->getStatus());
         $tmp['blueprintName'] = '';
         $tmp['parameters'] = '';
         $tmp['template'] = '';
         $diff = new Diff($output);
         try {
             $blueprint = $this->blueprintFactory->getBlueprintByStack($stack);
             $env = $stack->getUsedEnvVars();
             $diff->setStack($stack);
             $diff->setBlueprint($blueprint);
             $tmp['blueprintName'] = '<fg=green>' . $blueprint->getName() . '</>';
             if (count($env)) {
                 $tmp['blueprintName'] .= "\n" . wordwrap(Div::assocArrayToString($stack->getUsedEnvVars()), 80, "\n");
             }
             $tmp = array_merge($tmp, $diff->compare());
             if (isset($tmp['error']) && $tmp['error'] === true) {
                 $error = true;
             }
         } catch (BlueprintReferenceNotFoundException $e) {
             $tmp['blueprintName'] = '-';
             $tmp['parameters'] = '<fg=red>not found</>';
             $tmp['template'] = '<fg=red>not found</>';
             $error = true;
         } catch (BlueprintNotFoundException $e) {
             $tmp['blueprintName'] = '<fg=red>Not found: ' . $e->getBlueprintName() . '</>';
             $tmp['parameters'] = '<fg=red>not found</>';
             $tmp['template'] = '<fg=red>not found</>';
             $error = true;
         } catch (\Exception $e) {
             $tmp['blueprintName'] = '<fg=red>Exception: ' . $e->getMessage() . '</>';
             $tmp['parameters'] = '<fg=red>exception</>';
             $tmp['template'] = '<fg=red>exception</>';
             $error = true;
         }
         if (isset($tmp['error'])) {
             // so the column doesn't show on in the output table
             unset($tmp['error']);
         }
         $data[] = $tmp;
     }
     $output->writeln('');
     $table = new Table($output);
     $table->setHeaders(['Stack', 'Status', 'Blueprint', 'Parameters', 'Template']);
     $table->setRows($data);
     $table->render();
     $output->writeln('');
     $output->writeln("-> Run this to show a diff for a specific stack:");
     $output->writeln("{$GLOBALS['argv'][0]} stack:diff <stackName>");
     $output->writeln('');
     $output->writeln("-> Run this to update a live stack:");
     $output->writeln("{$GLOBALS['argv'][0]} blueprint:deploy -o <blueprintName>");
     $output->writeln('');
     return $error === true ? 1 : 0;
 }
Esempio n. 7
0
 /**
  * @test
  */
 public function testSwitchProfileComplex()
 {
     putenv('ACCOUNT=t');
     putenv('BASE_TYPE_VERSION=42');
     $profileManagerMock = $this->getMock('\\StackFormation\\Profile\\Manager', [], [], '', false);
     $profileManagerMock->method('getStackFactory')->willReturnCallback(function () {
         $stackFactoryMock = $this->getMock('\\StackFormation\\StackFactory', ['getStackOutput'], [], '', false);
         $stackFactoryMock->method('getStackOutput')->willReturnCallback(function ($stackName, $key) {
             return "DummyValue|{$stackName}|{$key}";
         });
         return $stackFactoryMock;
     });
     $config = new \StackFormation\Config([FIXTURE_ROOT . 'Config/blueprint.switch_profile.yml']);
     $valueResolver = new \StackFormation\ValueResolver\ValueResolver(null, $profileManagerMock, $config);
     $blueprintFactory = new \StackFormation\BlueprintFactory($config, $valueResolver);
     $blueprint = $blueprintFactory->getBlueprint('switch_profile_complex');
     $parameters = $blueprint->getParameters(true);
     $parameters = Div::flatten($parameters, 'ParameterKey', 'ParameterValue');
     $this->assertEquals('DummyValue|ecom-t-all-ami-types-42-stack|VarnishAmi', $parameters['VarnishAmi']);
 }