GenerateVclCommand.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\PageCache\Console\Command;
  7. use Magento\Framework\App\Config\ScopeConfigInterface;
  8. use Magento\Framework\Console\Cli;
  9. use Magento\Framework\Filesystem\DriverPool;
  10. use Magento\Framework\Filesystem\File\WriteFactory;
  11. use Magento\Framework\HTTP\PhpEnvironment\Request;
  12. use Magento\Framework\Serialize\Serializer\Json;
  13. use Magento\PageCache\Model\VclGeneratorInterfaceFactory;
  14. use Magento\PageCache\Model\Config;
  15. use Magento\PageCache\Model\Varnish\VclTemplateLocator;
  16. use Magento\Store\Model\ScopeInterface;
  17. use Symfony\Component\Console\Command\Command;
  18. use Symfony\Component\Console\Input\InputInterface;
  19. use Symfony\Component\Console\Input\InputOption;
  20. use Symfony\Component\Console\Output\OutputInterface;
  21. /**
  22. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  23. */
  24. class GenerateVclCommand extends Command
  25. {
  26. /**
  27. * Access list option name
  28. */
  29. const ACCESS_LIST_OPTION = 'access-list';
  30. /**
  31. * Backend host option name
  32. */
  33. const BACKEND_HOST_OPTION = 'backend-host';
  34. /**
  35. * Backend port option name
  36. */
  37. const BACKEND_PORT_OPTION = 'backend-port';
  38. /**
  39. * Varnish version option name
  40. */
  41. const EXPORT_VERSION_OPTION = 'export-version';
  42. /**
  43. * Grace period option name
  44. */
  45. const GRACE_PERIOD_OPTION = 'grace-period';
  46. /**
  47. * Output file option name
  48. */
  49. const OUTPUT_FILE_OPTION = 'output-file';
  50. /**
  51. * @var \Magento\Framework\Filesystem\Directory\WriteFactory
  52. */
  53. private $writeFactory;
  54. /**
  55. * @var VclGeneratorInterfaceFactory
  56. */
  57. private $vclGeneratorFactory;
  58. /**
  59. * @var array
  60. */
  61. private $inputToVclMap = [
  62. self::ACCESS_LIST_OPTION => 'accessList',
  63. self::BACKEND_PORT_OPTION => 'backendPort',
  64. self::BACKEND_HOST_OPTION => 'backendHost',
  65. self::GRACE_PERIOD_OPTION => 'gracePeriod',
  66. ];
  67. /**
  68. * @var ScopeConfigInterface
  69. */
  70. private $scopeConfig;
  71. /**
  72. * @var Json
  73. */
  74. private $serializer;
  75. /**
  76. * @inheritdoc
  77. */
  78. protected function configure()
  79. {
  80. $this->setName('varnish:vcl:generate')
  81. ->setDescription('Generates Varnish VCL and echos it to the command line')
  82. ->setDefinition($this->getOptionList());
  83. }
  84. /**
  85. * @param VclGeneratorInterfaceFactory $vclGeneratorFactory
  86. * @param WriteFactory $writeFactory
  87. * @param ScopeConfigInterface $scopeConfig
  88. * @param Json $serializer
  89. */
  90. public function __construct(
  91. VclGeneratorInterfaceFactory $vclGeneratorFactory,
  92. WriteFactory $writeFactory,
  93. ScopeConfigInterface $scopeConfig,
  94. Json $serializer
  95. ) {
  96. parent::__construct();
  97. $this->writeFactory = $writeFactory;
  98. $this->vclGeneratorFactory = $vclGeneratorFactory;
  99. $this->scopeConfig = $scopeConfig;
  100. $this->serializer = $serializer;
  101. }
  102. /**
  103. * @inheritdoc
  104. */
  105. protected function execute(InputInterface $input, OutputInterface $output)
  106. {
  107. $errors = $this->validate($input);
  108. if ($errors) {
  109. foreach ($errors as $error) {
  110. $output->writeln('<error>'.$error.'</error>');
  111. return Cli::RETURN_FAILURE;
  112. }
  113. }
  114. try {
  115. $outputFile = $input->getOption(self::OUTPUT_FILE_OPTION);
  116. $varnishVersion = $input->getOption(self::EXPORT_VERSION_OPTION);
  117. $vclParameters = array_merge($this->inputToVclParameters($input), [
  118. 'sslOffloadedHeader' => $this->getSslOffloadedHeader(),
  119. 'designExceptions' => $this->getDesignExceptions(),
  120. ]);
  121. $vclGenerator = $this->vclGeneratorFactory->create($vclParameters);
  122. $vcl = $vclGenerator->generateVcl($varnishVersion);
  123. if ($outputFile) {
  124. $writer = $this->writeFactory->create($outputFile, DriverPool::FILE, 'w+');
  125. $writer->write($vcl);
  126. $writer->close();
  127. } else {
  128. $output->writeln($vcl);
  129. }
  130. return Cli::RETURN_SUCCESS;
  131. } catch (\Exception $e) {
  132. $output->writeln('<error>'.$e->getMessage().'</error>');
  133. if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
  134. $output->writeln($e->getTraceAsString());
  135. }
  136. return Cli::RETURN_FAILURE;
  137. }
  138. }
  139. /**
  140. * Get list of options for the command
  141. *
  142. * @return InputOption[]
  143. */
  144. private function getOptionList()
  145. {
  146. return [
  147. new InputOption(
  148. self::ACCESS_LIST_OPTION,
  149. null,
  150. InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
  151. 'IPs access list that can purge Varnish',
  152. ['localhost']
  153. ),
  154. new InputOption(
  155. self::BACKEND_HOST_OPTION,
  156. null,
  157. InputOption::VALUE_REQUIRED,
  158. 'Host of the web backend',
  159. 'localhost'
  160. ),
  161. new InputOption(
  162. self::BACKEND_PORT_OPTION,
  163. null,
  164. InputOption::VALUE_REQUIRED,
  165. 'Port of the web backend',
  166. 8080
  167. ),
  168. new InputOption(
  169. self::EXPORT_VERSION_OPTION,
  170. null,
  171. InputOption::VALUE_REQUIRED,
  172. 'The version of Varnish file',
  173. VclTemplateLocator::VARNISH_SUPPORTED_VERSION_4
  174. ),
  175. new InputOption(
  176. self::GRACE_PERIOD_OPTION,
  177. null,
  178. InputOption::VALUE_REQUIRED,
  179. 'Grace period in seconds',
  180. 300
  181. ),
  182. new InputOption(
  183. self::OUTPUT_FILE_OPTION,
  184. null,
  185. InputOption::VALUE_REQUIRED,
  186. 'Path to the file to write vcl'
  187. ),
  188. ];
  189. }
  190. /**
  191. * @param InputInterface $input
  192. * @return array
  193. */
  194. private function inputToVclParameters(InputInterface $input)
  195. {
  196. $parameters = [];
  197. foreach ($this->inputToVclMap as $inputKey => $vclKey) {
  198. $parameters[$vclKey] = $input->getOption($inputKey);
  199. }
  200. return $parameters;
  201. }
  202. /**
  203. * Input validation
  204. *
  205. * @param InputInterface $input
  206. * @return array
  207. */
  208. private function validate(InputInterface $input)
  209. {
  210. $errors = [];
  211. if ($input->hasOption(self::BACKEND_PORT_OPTION)
  212. && ($input->getOption(self::BACKEND_PORT_OPTION) < 0
  213. || $input->getOption(self::BACKEND_PORT_OPTION) > 65535)
  214. ) {
  215. $errors[] = 'Invalid backend port value';
  216. }
  217. if ($input->hasOption(self::GRACE_PERIOD_OPTION)
  218. && $input->getOption(self::GRACE_PERIOD_OPTION) < 0
  219. ) {
  220. $errors[] = 'Grace period can\'t be lower than 0';
  221. }
  222. return $errors;
  223. }
  224. /**
  225. * Get ssl Offloaded header
  226. *
  227. * @return mixed
  228. */
  229. private function getSslOffloadedHeader()
  230. {
  231. return $this->scopeConfig->getValue(Request::XML_PATH_OFFLOADER_HEADER);
  232. }
  233. /**
  234. * Get design exceptions
  235. *
  236. * @return array
  237. */
  238. private function getDesignExceptions()
  239. {
  240. $expressions = $this->scopeConfig->getValue(
  241. Config::XML_VARNISH_PAGECACHE_DESIGN_THEME_REGEX,
  242. ScopeInterface::SCOPE_STORE
  243. );
  244. return $expressions ? $this->serializer->unserialize($expressions) : [];
  245. }
  246. }