_running_log = "running.log"; $this->_mysql_user = "iksop"; $this->_mysql_pass = "235r2342gtfsw"; $this->_mysql_root_pass = "235r2342gtfsw"; $this->_mysql_max_connections = 10000; $this->_mysql_link = "mysql:mysql"; $this->_running_env = "running.env"; $this->_host_env = "host.env"; $this->_docker_restart_default = "on-failure:10"; $this->_docker_restart_task = "on-failure"; $this->_docker_restart_always = "always"; $this->_network_name = "flowdat3"; $this->_user_system = ['users' => [ ['user' => 'admin', 'password' => 'admin', 'tenancy' => 1, 'email' => 'soporte@interlink.com.ar', 'extra' => '--super-admin '], ['user' => 'iksop', 'password' => 'gran5pe', 'tenancy' => 2, 'email' => 'admin@interlink.com.ar', 'extra' => ''], ['user' => 'interno', 'password' => 'gran5pe1nterno', 'tenancy' => 2, 'email' => 'admin@interlink.com.ar', 'extra' => ''] ]]; $this->_modules = array(); $this->_ansible_vars = array(); $this->_modules_all = $this->getModules(); $this->_add_nginx_links = false; } protected function getModules() { $dir = __DIR__ . "/Services/"; $files = scandir($dir); $modulesRead = []; $resp = []; foreach ($files as $file) { if (is_file($dir . $file) && $file != "InitialService.php") { $class = "FD3\\Services\\" . explode(".", $file)[0]; $object = new $class(); array_push($modulesRead, $object); } } // obtengo los modulos requeridos por obligacion foreach ($modulesRead as $key => $mod) { if ($mod->isRequired()) { $resp[$mod->getModuleName()] = $mod->getConfig(); unset($modulesRead[$key]); } } // obtengo los modulos sin dependencias foreach ($modulesRead as $key => $mod) { if (count($mod->getDepends()) == 0) { $resp[$mod->getModuleName()] = $mod->getConfig(); unset($modulesRead[$key]); } } // obtengo el resto de los modulos foreach ($modulesRead as $mod) { $resp[$mod->getModuleName()] = $mod->getConfig(); } return $resp; } protected function configure() { $this ->setName('make:installImages') ->setDescription('Create a new install.') ->setHelp('This command allows you to create a new installation...') ->addArgument('dir', InputArgument::REQUIRED, 'The directory where to create the installation.') ->addOption('host_ip', null, InputOption::VALUE_REQUIRED, 'Ip of the runnning host to be added to the /etc/hosts file, eventually', "127.0.1.1") ->addOption('domain', null, InputOption::VALUE_REQUIRED, 'Domain where the flowdat will be installed', "flowdat.net") ->addOption('client', null, InputOption::VALUE_REQUIRED, 'Client name, if is not provided uses, the dirname of the installation', false) ->addOption('ip_network_begin', null, InputOption::VALUE_OPTIONAL, 'Flowdat ip network configuration', "172.16.0.0") ->addOption('branch', null, InputOption::VALUE_OPTIONAL, 'Branch to install. Ej. v0.1.1', "latest") ->addOption('develop', null, InputOption::VALUE_OPTIONAL, 'If true or 1 then install images and source code.', false) ->addOption('public_ip', null, InputOption::VALUE_OPTIONAL, 'Public IP of server', false) ->addOption('ini_file', null, InputOption::VALUE_OPTIONAL, 'Ini file with git repositories urls', './modules.ini') ; } protected function colors(OutputInterface $output) { $green = new OutputFormatterStyle('green'); $output->getFormatter()->setStyle('green', $green); $blue = new OutputFormatterStyle('blue'); $output->getFormatter()->setStyle('blue', $blue); $red = new OutputFormatterStyle('red'); $output->getFormatter()->setStyle('red', $red); $bold = new OutputFormatterStyle(null, null, ['bold']); $output->getFormatter()->setStyle('bold', $bold); } protected function execute(InputInterface $input, OutputInterface $output) { try { $this->colors($output); // seteo todos los modulos a instalar por defecto $modules = $this->selectInstallModules($input, $output); $this->AddModules(explode(",", $modules)); $this->directory = $input->getArgument('dir'); if (!is_dir($this->directory)) { mkdir($this->directory, 0777, true); } if (file_exists($this->directory . "/" . $this->_running_log)) { $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('The ' . realpath($this->directory) . "/" . $this->_running_log . ' file exist. Read file (Y) or take parameters (N)? (Y/n)', true); if ($helper->ask($input, $output, $question)) { $this->setParametersFormFile($input); } } $this->_domain = $input->getOption("domain"); $this->_client = $input->getOption("client"); $this->_develop = $input->getOption("develop") === "true" || $input->getOption("develop") === "1"; $this->_network_ip = $input->getOption("ip_network_begin"); if (!$this->_client) { $this->_client = basename(realpath($this->directory)); } $version = $input->getOption("branch"); $internal_user_id = 2; $this->_ansible_vars["DOMAIN"] = $this->_domain; $this->_ansible_vars["CLIENT"] = $this->_client; $this->_ansible_vars["CMD_USERNAME"] = $this->_user_system['users'][$internal_user_id]['user']; $this->_ansible_vars["CMD_PASSWORD"] = $this->_user_system['users'][$internal_user_id]['password']; $this->_ansible_vars["ENV_LIST"] = "prod,dev,test"; $this->_ansible_vars["API_CIDR"] = "172.16.0.0/16"; $this->_ansible_vars["IK_SUBRED"] = "200.50.160.0/21"; $this->_ansible_vars["MYSQL_ROOT_PASSWORD"] = $this->_mysql_root_pass; $this->_add_nginx_links = true; $dObj = new DevOps\FileSystem(realpath($this->directory)); $dObj->dirExists()->realpath(); $this->_dObj = $dObj; // agrego las opciones del input a la configuracion _modues $this->addConfigOptions($input, $version); // creo el archivo de log de como se ejecuto $this->createFileRunning($input, $output); // cargo las fuentes a clonar $this->createGitClone($input); // creo el archivo docker-compose.yml $this->getDockerComposer($version, "docker.infra.flowdat.com/"); // escribo el archivo de host $this->writeHostsFile($input->getOption("host_ip")); // escribo el archivo con las variables de entorno $this->writeHostEnv(); // escribo los archivo oauth $this->writeOAUTH(); // escribo un archivo con variables para ansible $this->writeEnvVariables(); $dObj->file('install.yml')->content( yaml::dump(array( "install_dir" => realpath($this->directory), 'docker_apps' => implode(",", $this->_ansible_vars), 'domain' => $this->_domain, ) ) ); $dObj->file('ansible.cfg')->content( "[defaults]\n" . "inventory=inventory.ini\n" . "gather_timeout=30\n" ); // Copio el archivo hosts por defecto que reemplaza el /etc/hosts en cada container $path = $dObj->dirExists()->realpath()->getPath(); copy(getcwd() . "/hosts", $path . "/hosts"); $this->public_ip = $input->getOption('public_ip'); while (!filter_var($this->public_ip, FILTER_VALIDATE_IP)) { $helper = $this->getHelper('question'); $question = new Question('IP pública del cliente para acceder a Flowdat ? (Default: 127.0.0.1)', '127.0.0.1'); $this->public_ip = $helper->ask($input, $output, $question); } $this->addHosts(); // copio el playbook if ($this->_develop) { copy(getcwd() . "/playbook.yml", $path . "/playbook.yml"); } else { copy(getcwd() . "/playbookSupport.yml", $path . "/playbook.yml"); copy(getcwd() . "/get_supervisord_files.sh", $path . "/get_supervisord_files.sh"); // KEA selected for install, copy the file get_kea_files.sh // otherwise delete the file if exists in the path $keaFile = "{$path}/get_kea_files.sh"; if ($this->isModuleAvailable(new Kea())) { copy(getcwd() . "/get_kea_files.sh", $keaFile); } elseif (file_exists($keaFile) === true) { unlink($keaFile); } } // copio el script de base de datos inicial copy(getcwd() . "/mysql_scripts.sql", $path . "/mysql_scripts.sql"); // copio script mysql schema freeradius copy(getcwd() . "/mysql/freeradius/schema.sql", $path . "/freeradius_schema.sql"); // copio el docker-compose.service copy(getcwd() . "/docker-compose.service", $path . "/docker-compose.service"); } catch (\Throwable $t) { $output->writeln($t->getTraceAsString()); } finally { $this->_dObj = null; $this->_modules = null; } } /** * @param string $module Name of module. * @return bool Return TRUE if depends exists. */ public function needInstallModule($module) { foreach ($this->_modules as $key => $value) { if ($key == $module) { return true; } } return false; } /** * @param array $modules All modules selected. * @param array $depends All modules to depends. * @return bool Return TRUE if depends exists. */ public function checkDepends($modules, $depends) { if ($depends) { foreach ($depends as $depend) { if (in_array($depend, $modules)) { return true; } } } return false; } /** * @param InputInterface $input InputInterface * @param OutputInterface $output OutputInterface * @param bool $update * @return string Return all modules selected. */ public function selectInstallModules(InputInterface $input, OutputInterface $output, $update = false) { $modules = []; $output->writeln("Seleccione los módulos que desea instalar:"); foreach ($this->_modules_all as $name => $value) { if (isset($value['REQUIRED']) && $value['REQUIRED']) { $modules[] = $name; $output->writeln("Se instala el modulo $name, por ser una dependencia obligatoria"); } else { if ($this->checkDepends($modules, $value['DEPENDS'])) { $modules[] = $name; $value['REQUIRED'] = true; $output->writeln("Se instala el modulo $name, por tener las siguientes dependencias " . implode(",", $value['DEPENDS']) . ""); } else { $helper = $this->getHelper('question'); $defaultQuestionYes = "(Y/n)"; $defaultQuestionNo = "(y/N)"; $def = $defaultQuestionYes; if (!$value["DEFAULTINSTALATION"]) { $def = $defaultQuestionNo; } if ($value['INSTALLED']) { $installed = " *** MODULO YA INSTALADO *** "; if ($update) { $def = $defaultQuestionYes; } } else { $installed = ""; if ($update) { $def = $defaultQuestionNo; } } $question = new ConfirmationQuestion($installed . (isset($value['HELP']) ? ($value['HELP'] . ". ") : "") . strtoupper($name) . "? $def ", $defaultQuestionYes == $def); if ($helper->ask($input, $output, $question)) { $modules [] = $name; $value['REQUIRED'] = true; } } } } $modules = implode(",", $modules); return $modules; } /** * @return array Retorna un array con los host como key el dominio como valor. */ function getHostEnv() { $resp = array(); // agrego todos los host. Esto se necesita para cuando no se instala completo foreach ($this->_modules_all as $key => $values) { if (isset($values['HOST_ENV']) && $values['HOST_ENV']) { $resp ["HOST_" . strtoupper($key)] = ""; } } // agrego las url solo a los que voy a instalar foreach ($this->_modules as $key => $values) { if (isset($values['HOST_ENV']) && $values['HOST_ENV']) { $resp ["HOST_" . strtoupper($key)] = $this->getDomain($key); } } return $resp; } function getHostConfig($config_ip) { $resp = array(); foreach ($this->_modules as $key => $values) { if (isset($values['HOST_ENV']) && $values['HOST_ENV']) { $resp [$this->getDomain($key)] = $config_ip; } } return $resp; } function getDockerComposer($version = "latest", $registry = "docker.infra.flowdat.com/") { $composer = new FileFormat("../", "3.7"); $this->registerVolumes($composer); $nc = new NetworkConfig(); $nc->addDriver()->addSubnetGateway("172.16.0.0/16"); $composer->getNetwork()->addDriver($this->_network_name)->addConfig($this->_network_name, $nc); $base_vars = array( "version" => $version, "host_env_file" => $this->_host_env, "registry" => $registry); $ip = explode(".", $this->_network_ip); array_pop($ip); $ip = implode(".", $ip); foreach ($this->_modules_all as $module => $env) { if (strpos($module, "genieacs") !== false) { $module = str_replace("-", "_", $module); } $class = "FD3\\Services\\" . ucfirst($module); $object = new $class(); $object ->setRelease($this) ->setComposer($composer) ->setConfigVar($base_vars) ->setIp($ip) ->setProduction(!$this->_develop) ->add(); } $this->_dObj->file("docker-compose.yml")->content($composer->render()); // escribo un archivo inventory.ini por defecto para no tener que lanzar los docker $this->writeInventory($composer); } /** * Write hosts file with ips of docker containers */ protected function addHosts() { $composer = new FileFormat("../", "3.7"); $ip = explode(".", $this->_network_ip); array_pop($ip); $ip = implode(".", $ip); $ips = []; foreach ($this->_modules_all as $module => $env) { if (strpos($module, "genieacs") !== false) { $module = str_replace("-", "_", $module); } $class = "FD3\\Services\\" . ucfirst($module); $object = new $class(); $object ->setRelease($this) ->setComposer($composer) ->setIp($ip) ->setProduction(!$this->_develop) ->add(); if ($this->needInstallModule($module)) { $ips[$module] = $object->generateIP(); } } $path = $this->_dObj->dirExists()->realpath()->getPath(); $contents = file_get_contents($path . "/hosts") . "\n"; if (count($ips)) { ksort($ips); } foreach ($ips as $module => $ip) { $contents .= "{$ip} {$module}\n"; } $modules = [ new Base(), new Ftth(), new Cablemodem(), new Stats(), new Dhcp(), new Radius(), ]; foreach ($modules as $module) { if ($this->isModuleAvailable($module)) { $domain = $this->getDomain(($module)->getModuleName()); $contents .= "{$this->public_ip} {$domain}\n"; } } file_put_contents($path . "/hosts", $contents); } /** * Crea un array con la configuracion de los modulos. * @param InputInterface $input Contiene el input. * @param String $version Version to install. */ protected function addConfigOptions(InputInterface $input, $version) { $file = $input->getOption('ini_file'); $repositories = parse_ini_file($file, true); if (strtolower($version) === 'latest') { $version = "master"; } foreach ($this->_modules as $key => $values) { $modifyKey = false; $new_key = $key; if ($new_key == (new Jsendpoint())->getModuleName() || $new_key == (new Jsonep_mysql())->getModuleName() || $new_key == (new Jsonep_mongo())->getModuleName()) { // los jsendpoint estan dentro del statsd $new_key = "statsd"; $modifyKey = true; } elseif ($new_key == (new Genieacs_cwmp())->getModuleName() || $new_key == (new Genieacs_fs())->getModuleName() || $new_key == (new Genieacs_nbi())->getModuleName() || $new_key == (new Genieacs_gui())->getModuleName()) { // agrego cualquier genieacs $new_key = "genieacs"; $modifyKey = true; } foreach ($repositories as $keyRepo => $valueRepo) { if ($new_key == $keyRepo) { if ($modifyKey) { $this->_modules[$new_key]['repo'] = $repositories[$keyRepo]["repo"]; $this->_modules[$new_key]['ref'] = $version; } else { $this->_modules[$key]['repo'] = $repositories[$keyRepo]["repo"]; $this->_modules[$key]['ref'] = $version; } } } } } /** * Crea un array con las direcciones de a clonar. */ protected function createGitClone(InputInterface $input, $version = 'latest') { $clone = array(); $modules = array_keys($this->_modules); foreach ($modules as $name) { if (isset($this->_modules[$name]["repo"]) && isset($this->_modules[$name]["ref"])) { $clone[$name] = array( 'url' => $this->_modules[$name]["repo"], 'branch' => $this->_modules[$name]["ref"] ); } } if ($this->_develop) { // agrego fuentes que no son modulos $file = $input->getOption('ini_file'); $repositories = parse_ini_file($file, true); if (strtolower($version) === 'latest') { $version = "master"; } $mod = 'connect'; $clone[$mod] = array( 'url' => $repositories[$mod]["repo"], 'branch' => $version ); $mod = 'netmiko'; $clone[$mod] = array( 'url' => $repositories[$mod]["repo"], 'branch' => $version ); $mod = 'ciscoconf'; $clone[$mod] = array( 'url' => $repositories[$mod]["repo"], 'branch' => $version ); } $this->_dObj->file("git.ini")->writeIniConfig($clone); } /** * Crea un archivo conlos parametros con los que se corrio el script. * @param InputInterface $input Contiene el input * @param OutputInterface $output Contiene el output */ protected function createFileRunning(InputInterface $input, OutputInterface $output) { $file = array(); $file ["Running"] = array("date" => gmdate('Y-m-d h:i:s')); $file ["Arguments"] = $input->getArguments(); $file ["Options"] = $input->getOptions(); $file ["Options"]["modules"] = implode(",", array_keys($this->_modules)); $output->writeln("Writing " . $this->_dObj->getPath() . "/" . $this->_running_log); $this->_dObj->file($this->_running_log)->writeIniConfig($file); } /** * @param string $module Contiene el nombre del modulo. * @param array $extras Contiene variables de entorno extra. * @return string|array Retorna un array con los datos de virtual host. */ function getEnviromentVarialbes($module, $extras = array()) { $env = ""; if ($module != null) { foreach ($this->_modules as $nameApp => $app) { if (isset($app['VAR_ENV']) && $nameApp == $module) { foreach ($app['VAR_ENV'] as $key => $value) { if ($key == 'VIRTUAL_HOST') { $env .= "VIRTUAL_HOST=" . $this->getDomain($module) . "\n"; } else { $env .= $key . "=" . $value . "\n"; } } } } } foreach ($extras as $key => $value) { $env .= $key . "=" . $value . "\n"; } return $env; } /** * Crea el archivo modulo.oauth.env */ protected function writeOAUTH() { $oautModules = ""; foreach ($this->_modules as $nameApp => $app) { if (isset($app['OAUTH']) && $app['OAUTH']) { if (!file_exists(realpath($this->directory) . $nameApp . ".oauth.env")) { $this->_dObj->file($nameApp . ".oauth.env")->content(""); $oautModules = $oautModules . $nameApp . ","; } } } $this->_ansible_vars["MODULES_INSTALL"] = "base," . substr($oautModules, 0, strlen($oautModules) - 1); } /** * Crea el archivo host.env */ protected function writeHostEnv() { $hostEnvConfig = $this->getHostEnv(); $env_content = ""; foreach ($hostEnvConfig as $var => $val) { $env_content .= $var . "=" . $val . "\n"; } $this->_dObj->file($this->_host_env)->content($env_content); } /** * Crea el archivo hostsDile * @param string $config_ip Contiene la ip. */ protected function writeHostsFile($config_ip) { $hostConfig = $this->getHostConfig($config_ip); $hostfile_content = ""; foreach ($hostConfig as $host => $ip) { $hostfile_content .= $ip . "\t" . $host . "\n"; } $this->_dObj->file("hostsFile")->content($hostfile_content); } /** * Crea un archivo con las variables de entorno particulares del modulo. * @param string $name Contiene el nombre del archivo. * @param string $module Contiene el nombre del modulo. * @param array $extras Contiene un array con las variables extras. */ public function writeVariablesEnviroment($name, $module = null, $extras = array()) { $this->_dObj->file($name)->content( $this->getEnviromentVarialbes($module, $extras)); } /** * Funcion que agrega el build de acuerdo en la configuracion. * @param string $module Contiene el nombre del modulo. * @param FileFormat $composer Contiene el objeto FileFormat. */ public function addBuild($module, FileFormat $composer) { if (isset($this->_modules[$module]['build']) && filter_var($this->_modules[$module]['build'], FILTER_VALIDATE_BOOLEAN)) { try { $composer->service($module)->build("./$module/"); } catch (ServiceNotFoundException $ignore) { } } } /** * Funcion que setea los valores que se lean desde el archivo running.log. * Solo se reemplazan las opciones. * Si se toman los argumentos puede pisar el directorio de destino y a lo mejor se quiere replicar la instalacion en * otro directorio. * @param InputInterface $input contiene el input */ protected function setParametersFormFile(InputInterface $input) { $parameters = parse_ini_file($input->getArgument('dir') . "/" . $this->_running_log, true); foreach ($parameters["Options"] as $key => $value) { $this->_option_repo[$key] = $value; } } /** * @param string $module Contiene el nombre del modulo. * @return string Retorna el dominio para el modulo. */ public function getDomain($module) { return $module . "." . $this->_client . "." . $this->_domain; } /** * @param array $modules Contiene los modulos a implementar */ protected function AddModules($modules) { foreach ($modules as $value) { if (array_key_exists($value, $this->_modules_all)) { $this->_modules[$value] = $this->_modules_all[$value]; } } } /** * Crea el archivo con las variables para ejecutar el ansible. */ protected function writeEnvVariables() { $tmp = ""; foreach ($this->_ansible_vars as $key => $value) { $tmp = $tmp . "$key=$value\n"; } $this->_dObj->file(str_replace(".log", ".env", $this->_running_log)) ->content($tmp); } /** * Crea el archivo con las variables para ejecutar el ansible. */ protected function writeInventory(FileFormat $composer) { $tmp = ""; $all = "[all]\n"; $prefix = basename(realpath($this->directory)); foreach ($composer->getServices() as $key => $value) { $tmp .= "[$key]\n"; $tmp .= $prefix . "_" . $key . "_1\n\n"; $all .= $prefix . "_" . $key . "_1\n"; } $this->_dObj->file("inventory.ini")->content($tmp . $all); } /** * Funcion que agrega links nginx a los modulos principales (para instalacion dev) * @param string $module Contiene el nombre del modulo. * @param FileFormat $composer Contiene el objeto FileFormat. * @throws ServiceNotFoundException */ public function addNginxLinks($module, FileFormat $composer) { if ($this->_add_nginx_links) { if ($this->isModuleAvailable(new Base())) { $composer->service($module)->addLinks((new Nginx())->getModuleName(), $this->getDomain((new Base())->getModuleName())); } if ($this->isModuleAvailable(new Ftth())) { $composer->service($module)->addLinks((new Nginx())->getModuleName(), $this->getDomain((new Ftth())->getModuleName())); } if ($this->isModuleAvailable(new Cablemodem())) { $composer->service($module)->addLinks((new Nginx())->getModuleName(), $this->getDomain((new Cablemodem())->getModuleName())); } if ($this->isModuleAvailable(new Stats())) { $composer->service($module)->addLinks((new Nginx())->getModuleName(), $this->getDomain((new Stats())->getModuleName())); } if ($this->isModuleAvailable(new Dhcp())) { $composer->service($module)->addLinks((new Nginx())->getModuleName(), $this->getDomain((new Dhcp())->getModuleName())); } if ($this->isModuleAvailable(new Radius())) { $composer->service($module)->addLinks((new Nginx())->getModuleName(), $this->getDomain((new Radius())->getModuleName())); } } } /** * Register volumes only for installed modules * @param FileFormat $composer */ protected function registerVolumes(FileFormat $composer) { if ($this->isModuleAvailable(new Pma())) { $composer->getVolumes()->addVolumen(Pma::PMA_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Swagger())) { $composer->getVolumes()->addVolumen(Swagger::SWAGGER_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Base())) { $composer->getVolumes() ->addVolumen(Base::BASE_SOCKET_VOLUMEN, 'local') ->addVolumen(Nginx::BASE_NGINX_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Cablemodem())) { $composer->getVolumes() ->addVolumen(Cablemodem::CABLEMODEM_SOCKET_VOLUMEN, 'local') ->addVolumen(Nginx::CABLEMODEM_NGINX_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Dhcp())) { $composer->getVolumes() ->addVolumen(Dhcp::DHCP_SOCKET_VOLUMEN, 'local') ->addVolumen(Dhcp::DHCP_KEA_VOLUMEN, 'local') ->addVolumen(Nginx::DHCP_NGINX_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Ftth())) { $composer->getVolumes() ->addVolumen(Ftth::FTTH_SOCKET_VOLUMEN, 'local') ->addVolumen(Ftth::FTTH_SUPERVISORD_VOLUMEN, 'local') ->addVolumen(Nginx::FTTH_NGINX_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Radius())) { $composer->getVolumes() ->addVolumen(Radius::RADIUS_SOCKET_VOLUMEN, 'local') ->addVolumen(Nginx::RADIUS_NGINX_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Stats())) { $composer->getVolumes() ->addVolumen(Stats::STATS_SOCKET_VOLUMEN, 'local') ->addVolumen(Stats::STATS_SUPERVISORD_VOLUMEN, 'local') ->addVolumen(Nginx::STATS_NGINX_VOLUMEN, 'local'); } if ($this->isModuleAvailable(new Api())) { $composer->getVolumes() ->addVolumen(Api::API_SOCKET_VOLUMEN, 'local') ->addVolumen(Nginx::API_NGINX_VOLUMEN, 'local'); } } public function isModuleAvailable(InitialService $object) { return array_key_exists($object->getModuleName(), $this->_modules); } }