Sindbad~EG File Manager
<?php
/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2022 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/
namespace Glpi\Console\Migration;
use CommonDBTM;
use Computer;
use ComputerModel;
use Datacenter;
use DB;
use DCRoom;
use Glpi\Console\AbstractCommand;
use Glpi\Toolbox\Sanitizer;
use Item_Rack;
use Monitor;
use MonitorModel;
use NetworkEquipment;
use NetworkEquipmentModel;
use PassiveDCEquipment;
use PassiveDCEquipmentModel;
use PDU;
use PDUModel;
use Peripheral;
use PeripheralModel;
use Plugin;
use Rack;
use RackModel;
use RackType;
use State;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
class RacksPluginToCoreCommand extends AbstractCommand
{
/**
* Error code returned if plugin version or plugin data is invalid.
*
* @var integer
*/
const ERROR_PLUGIN_VERSION_OR_DATA_INVALID = 1;
/**
* Error code returned if import failed.
*
* @var integer
*/
const ERROR_PLUGIN_IMPORT_FAILED = 1;
/**
* Version of Racks plugin required for this migration.
* @var string
*/
const RACKS_REQUIRED_VERSION = '1.8.0';
/**
* Choice value for other type: ignore.
* @var string
*/
const OTHER_TYPE_CHOICE_IGNORE = 'i';
/**
* Choice value for other type: computer.
* @var string
*/
const OTHER_TYPE_CHOICE_COMPUTER = 'c';
/**
* Choice value for other type: network equipment.
* @var string
*/
const OTHER_TYPE_CHOICE_NETWORKEQUIPEMENT = 'n';
/**
* Choice value for other type: peripheral.
* @var string
*/
const OTHER_TYPE_CHOICE_PERIPHERAL = 'p';
/**
* Choice value for other type: pdu.
* @var string
*/
const OTHER_TYPE_CHOICE_PDU = 'u';
/**
* Choice value for other type: monitor.
* @var string
*/
const OTHER_TYPE_CHOICE_MONITOR = 'm';
/**
* Choice value for other type: passive device.
* @var string
*/
const OTHER_TYPE_CHOICE_PASSIVEDCEQUIPEMENT = 'd';
/**
* Datacenter on which rooms will be created.
*
* @var integer
*/
private $datacenter_id;
/**
* Room on which racks will be placed if no corresponding room found.
*
* @var integer
*/
private $fallback_room_id;
/**
* Imported elements mapping.
*
* @var array
*/
private $elements_mapping;
protected function configure()
{
parent::configure();
$this->setName('glpi:migration:racks_plugin_to_core');
$this->setDescription(__('Migrate Racks plugin data into GLPI core tables'));
$this->addOption(
'ignore-other-elements',
'i',
InputOption::VALUE_NONE,
__('Ignore "PluginRacksOther" models and elements')
);
$this->addOption(
'skip-errors',
's',
InputOption::VALUE_NONE,
__('Do not exit on import errors')
);
$this->addOption(
'truncate',
't',
InputOption::VALUE_NONE,
__('Remove existing core data')
);
$this->addOption(
'update-plugin',
'u',
InputOption::VALUE_NONE,
sprintf(
__('Run Racks plugin update (you need version %s files to do this)'),
self::RACKS_REQUIRED_VERSION
)
);
$this->addOption(
'without-plugin',
'w',
InputOption::VALUE_NONE,
sprintf(
__('Enable migration without plugin files (we cannot validate that plugin data are compatible with supported %s version)'),
self::RACKS_REQUIRED_VERSION
)
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->elements_mapping = []; // Clear elements mapping
$no_interaction = $input->getOption('no-interaction');
if (!$no_interaction) {
// Ask for confirmation (unless --no-interaction)
$output->writeln(
[
__('You are about to launch migration of Racks plugin data into GLPI core tables.'),
__('It is better to make a backup of your existing data before continuing.')
]
);
$this->askForConfirmation(false);
}
if (!$this->checkPlugin()) {
return self::ERROR_PLUGIN_VERSION_OR_DATA_INVALID;
}
if ($input->getOption('truncate')) {
$this->cleanCoreTables();
}
if (!$this->migratePlugin()) {
return self::ERROR_PLUGIN_IMPORT_FAILED;
}
$output->writeln('<info>' . __('Migration done.') . '</info>');
return 0; // Success
}
/**
* Check that plugin state and existing data are OK for migration.
*
* @throws LogicException
*
* @return boolean
*/
private function checkPlugin()
{
$check_version = !$this->input->getOption('without-plugin');
if ($check_version) {
$this->output->writeln(
'<comment>' . __('Checking plugin version...') . '</comment>',
OutputInterface::VERBOSITY_VERBOSE
);
$plugin = new Plugin();
$plugin->checkPluginState('racks');
if (!$plugin->getFromDBbyDir('racks')) {
$message = __('Racks plugin is not part of GLPI plugin list. It has never been installed or has been cleaned.')
. ' '
. sprintf(
__('You have to install Racks plugin files in version %s to be able to continue.'),
self::RACKS_REQUIRED_VERSION
);
$this->output->writeln(
[
'<error>' . $message . '</error>',
],
OutputInterface::VERBOSITY_QUIET
);
return false;
}
$is_version_ok = '1.8.0' === $plugin->fields['version'];
if (!$is_version_ok) {
$message = sprintf(
__('You have to install Racks plugin files in version %s to be able to continue.'),
self::RACKS_REQUIRED_VERSION
);
$this->output->writeln(
'<error>' . $message . '</error>',
OutputInterface::VERBOSITY_QUIET
);
return false;
}
$is_installable = in_array(
$plugin->fields['state'],
[
Plugin::TOBECLEANED, // Can be in this state if check was done without the plugin dir
Plugin::NOTINSTALLED, // Can be not installed if plugin has been cleaned in plugin list
Plugin::NOTUPDATED, // Plugin 1.8.0 version has never been installed
]
);
if ($is_installable) {
if ($this->input->getOption('update-plugin')) {
$message = sprintf(
__('Migrating plugin to %s version...'),
self::RACKS_REQUIRED_VERSION
);
$this->output->writeln(
'<info>' . $message . '</info>',
OutputInterface::VERBOSITY_NORMAL
);
ob_start();
$plugin->install($plugin->fields['id']);
ob_end_clean();
// Reload and check migration result
$plugin->getFromDB($plugin->fields['id']);
if (!in_array($plugin->fields['state'], [Plugin::TOBECONFIGURED, Plugin::NOTACTIVATED])) {
$message = sprintf(
__('Plugin migration to %s version failed.'),
self::RACKS_REQUIRED_VERSION
);
$this->output->writeln(
'<error>' . $message . '</error>',
OutputInterface::VERBOSITY_QUIET
);
return false;
}
} else {
$message = sprintf(
__('Racks plugin data has to be updated to %s version. It can be done using the --update-plugin option.'),
self::RACKS_REQUIRED_VERSION
);
$this->output->writeln(
'<comment>' . $message . '</comment>',
OutputInterface::VERBOSITY_QUIET
);
return false;
}
}
$is_state_ok = in_array(
$plugin->fields['state'],
[
Plugin::ACTIVATED, // Should not be possible as 1.8.0 is not compatible with 9.3
Plugin::TOBECONFIGURED, // Should not be possible as check_config of plugin returns always true
Plugin::NOTACTIVATED,
]
);
if (!$is_state_ok) {
// Should not happens as installation should put plugin in awaited state
throw new \Symfony\Component\Console\Exception\LogicException('Unexpected plugin state.');
}
}
$rack_tables = [
'glpi_plugin_racks_itemspecifications',
'glpi_plugin_racks_others',
'glpi_plugin_racks_othermodels',
'glpi_plugin_racks_racks',
'glpi_plugin_racks_racks_items',
'glpi_plugin_racks_rackmodels',
'glpi_plugin_racks_racktypes',
'glpi_plugin_racks_rackstates',
'glpi_plugin_racks_roomlocations',
];
$missing_tables = false;
foreach ($rack_tables as $table) {
if (!$this->db->tableExists($table)) {
$this->output->writeln(
'<error>' . sprintf(__('Racks plugin table "%s" is missing.'), $table) . '</error>',
OutputInterface::VERBOSITY_QUIET
);
$missing_tables = true;
}
}
if ($missing_tables) {
$this->output->writeln(
'<error>' . __('Migration cannot be done.') . '</error>',
OutputInterface::VERBOSITY_QUIET
);
return false;
}
return true;
}
/**
* Clean data from core tables.
*
* @throws RuntimeException
*/
private function cleanCoreTables()
{
$core_tables = [
'glpi_datacenters',
'glpi_dcrooms',
'glpi_items_racks',
'glpi_pdus',
'glpi_racks',
'glpi_rackmodels',
'glpi_racktypes',
'glpi_passivedcequipments',
'glpi_passivedcequipmenttypes',
'glpi_passivedcequipmentmodels',
];
foreach ($core_tables as $table) {
$result = $this->db->query('TRUNCATE ' . $this->db->quoteName($table));
if (!$result) {
throw new \Symfony\Component\Console\Exception\RuntimeException(
sprintf('Unable to truncate table "%s"', $table)
);
}
}
}
private function migratePlugin()
{
$no_interaction = $this->input->getOption('no-interaction');
$skip_errors = $this->input->getOption('skip-errors');
// Create datacenter
$this->datacenter_id = $this->createDatacenter();
if (null === $this->datacenter_id && !$skip_errors) {
return false;
}
if (!$this->input->getOption('ignore-other-elements')) {
if ($no_interaction) {
$this->output->writeln(
'<comment>' . __('Other models and items cannot be migrated when --no-interaction option is used.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
} else {
if (!$this->importOtherElements() && !$skip_errors) {
return false;
}
}
}
$failure = (!$this->importItemsSpecifications() && !$skip_errors)
|| (!$this->importRackModels() && !$skip_errors)
|| (!$this->importRackTypes() && !$skip_errors)
|| (!$this->importRackStates() && !$skip_errors)
|| (!$this->importRooms() && !$skip_errors)
|| (!$this->importRacks() && !$skip_errors)
|| (!$this->importRackItems() && !$skip_errors);
return !$failure;
}
/**
* Create temporary datacenter.
*
* @return null|integer Datacenter id, or null in case of failure
*/
private function createDatacenter()
{
$this->output->writeln(
'<comment>' . __('Creating datacenter...') . '</comment>',
OutputInterface::VERBOSITY_VERBOSE
);
$dc = new Datacenter();
$dc_fields = [
'name' => 'Temp Datacenter (from racks plugin migration script)',
];
if (!($dc_id = $dc->getFromDBByCrit($dc_fields))) {
$dc_id = $dc->add($dc_fields);
}
if (false === $dc_id) {
$this->outputImportError(
'<error>' . __('Unable to create datacenter.') . '</error>'
);
return null;
}
return $dc_id;
}
/**
* Import other models and items.
*
* @throws LogicException
*
* @return boolean True in case of success, false in case of errors.
*/
private function importOtherElements()
{
$has_errors = false;
// Import other models
$this->output->writeln(
'<comment>' . __('Importing other models...') . '</comment>',
OutputInterface::VERBOSITY_VERBOSE
);
$othermodels_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_othermodels'
]
);
if ($count_othermodels = $othermodels_iterator->count()) {
$this->output->writeln(
[
'<comment>' . __('Other items do not exist in GLPI core.') . '</comment>',
sprintf(
__('We found %d models for other items. For each, we will ask you where you want to import it.'),
$count_othermodels
),
],
OutputInterface::VERBOSITY_QUIET
);
foreach ($othermodels_iterator as $othermodel) {
$model_label = $othermodel['name'];
if (strlen($othermodel['comment'])) {
$model_label .= ' (' . $othermodel['comment'] . ')';
}
/** @var QuestionHelper $question_helper */
$question_helper = $this->getHelper('question');
$answer = $question_helper->ask(
$this->input,
$this->output,
new ChoiceQuestion(
sprintf(__('Where do you want to import "%s"?'), $model_label),
[
self::OTHER_TYPE_CHOICE_COMPUTER => Computer::getTypeName(1),
self::OTHER_TYPE_CHOICE_NETWORKEQUIPEMENT => NetworkEquipment::getTypeName(1),
self::OTHER_TYPE_CHOICE_PERIPHERAL => Peripheral::getTypeName(1),
self::OTHER_TYPE_CHOICE_PDU => PDU::getTypeName(1),
self::OTHER_TYPE_CHOICE_MONITOR => Monitor::getTypeName(1),
self::OTHER_TYPE_CHOICE_PASSIVEDCEQUIPEMENT => PassiveDCEquipment::getTypeName(1),
self::OTHER_TYPE_CHOICE_IGNORE => __('Ignore (default)'),
],
self::OTHER_TYPE_CHOICE_IGNORE
)
);
if (self::OTHER_TYPE_CHOICE_IGNORE === $answer) {
continue;
}
$new_itemtype = null;
$new_model_itemtype = null;
switch ($answer) {
case self::OTHER_TYPE_CHOICE_COMPUTER:
$new_itemtype = Computer::class;
$new_model_itemtype = ComputerModel::class;
break;
case self::OTHER_TYPE_CHOICE_NETWORKEQUIPEMENT:
$new_itemtype = NetworkEquipment::class;
$new_model_itemtype = NetworkEquipmentModel::class;
break;
case self::OTHER_TYPE_CHOICE_PERIPHERAL:
$new_itemtype = Peripheral::class;
$new_model_itemtype = PeripheralModel::class;
break;
case self::OTHER_TYPE_CHOICE_PDU:
$new_itemtype = PDU::class;
$new_model_itemtype = PDUModel::class;
break;
case self::OTHER_TYPE_CHOICE_MONITOR:
$new_itemtype = Monitor::class;
$new_model_itemtype = MonitorModel::class;
break;
case self::OTHER_TYPE_CHOICE_PASSIVEDCEQUIPEMENT:
$new_itemtype = PassiveDCEquipment::class;
$new_model_itemtype = PassiveDCEquipmentModel::class;
break;
}
if (null === $new_model_itemtype) {
throw new \Symfony\Component\Console\Exception\LogicException(
sprintf('Answer "%s" has no corresponding itemtype.', $answer)
);
}
$new_model = new $new_model_itemtype();
$new_model_fields = Sanitizer::sanitize([
'name' => $othermodel['name'],
'comment' => $othermodel['comment'],
]);
if (
!($new_model_id = $new_model->getFromDBByCrit($new_model_fields))
&& !($new_model_id = $new_model->add($new_model_fields))
) {
$has_errors = true;
$message = sprintf(__('Unable to import other model "%s".'), $model_label);
$this->outputImportError($message);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
$this->addElementToMapping(
'PluginRacksOtherModel',
$othermodel['id'],
$new_model_itemtype,
$new_model_id
);
// Import items from model
$message = sprintf(__('Importing items from model "%s"...'), $model_label);
$this->output->writeln(
'<comment>' . $message . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$otheritems_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_others',
'WHERE' => [
'plugin_racks_othermodels_id' => $othermodel['id'],
],
]
);
if ($otheritems_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $otheritems_iterator->count());
$progress_bar->start();
$fk_new_model = getForeignKeyFieldForItemType($new_model_itemtype);
foreach ($otheritems_iterator as $otheritem) {
$progress_bar->advance(1);
$new_item_fields = Sanitizer::sanitize([
'name' => strlen($otheritem['name'])
? $otheritem['name']
: $otheritem['id'],
'entities_id' => $otheritem['entities_id'],
$fk_new_model => $new_model_id
]);
$new_item = new $new_itemtype();
if (!($new_item_id = $new_item->add($new_item_fields))) {
$has_errors = true;
$message = sprintf(
__('Unable to import other item "%s".'),
$new_item_fields['name']
);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
$this->addElementToMapping(
'PluginRacksOther',
$otheritem['id'],
$new_itemtype,
$new_item_id
);
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No items found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
}
}
return !$has_errors;
}
/**
* Import items specifications.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importItemsSpecifications()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing items specifications...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$specs_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_itemspecifications',
'ORDER' => 'id ASC'
]
);
if ($specs_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $specs_iterator->count());
$progress_bar->start();
foreach ($specs_iterator as $spec) {
$progress_bar->advance(1);
$message = sprintf(
__('Importing specifications for model %s (%s)...'),
$spec['itemtype'],
$spec['model_id']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$model = $this->getCorrespondingItem($spec['itemtype'], $spec['model_id']);
if (null === $model) {
$message = sprintf(
__('Model %s (%s) not found.'),
$spec['itemtype'],
$spec['model_id']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERBOSE
);
continue;
}
$model_input = [
'id' => $model->fields['id'],
'required_units' => $spec['size'],
'depth' => ($spec['length'] == 1 ? 1 : 0.5),
'weight' => $spec['weight'],
'is_half_rack' => 0,
'power_connections' => $spec['nb_alim'],
];
if (!$model->update($model_input)) {
$has_errors = true;
$message = sprintf(
__('Unable to update model %s (%s).'),
$spec['itemtype'],
$spec['model_id']
);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No items specifications found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Import rack models.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importRackModels()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing rack models...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$models_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_rackmodels',
]
);
if ($models_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $models_iterator->count());
$progress_bar->start();
foreach ($models_iterator as $old_model) {
$progress_bar->advance(1);
$message = sprintf(
__('Importing rack model "%s"...'),
$old_model['name']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$rackmodel = new RackModel();
$rackmodel_fields = Sanitizer::sanitize(
[
'name' => $old_model['name'],
'comment' => $old_model['comment'],
]
);
if (
!($rackmodel_id = $rackmodel->getFromDBByCrit($rackmodel_fields))
&& !($rackmodel_id = $rackmodel->add($rackmodel_fields))
) {
$has_errors = true;
$message = sprintf(__('Unable to import rack model "%s".'), $old_model['name']);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
$this->addElementToMapping(
'PluginRacksRackModel',
$old_model['id'],
RackModel::class,
$rackmodel_id
);
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No rack models found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Import rack types.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importRackTypes()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing rack types...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$types_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_racktypes',
]
);
if ($types_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $types_iterator->count());
$progress_bar->start();
foreach ($types_iterator as $old_type) {
$progress_bar->advance(1);
$message = sprintf(
__('Importing rack type "%s"...'),
$old_type['name']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$racktype = new RackType();
$racktype_fields = Sanitizer::sanitize(
[
'name' => $old_type['name'],
'entities_id' => $old_type['entities_id'],
'is_recursive' => $old_type['is_recursive'],
'comment' => $old_type['comment'],
]
);
if (
!($racktype_id = $racktype->getFromDBByCrit($racktype_fields))
&& !($racktype_id = $racktype->add($racktype_fields))
) {
$has_errors = true;
$message = sprintf(__('Unable to import rack type "%s".'), $old_type['name']);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
$this->addElementToMapping(
'PluginRacksRackType',
$old_type['id'],
RackType::class,
$racktype_id
);
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No rack models found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Import rack states.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importRackStates()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing rack states...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$states_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_rackstates',
]
);
if ($states_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $states_iterator->count());
$progress_bar->start();
foreach ($states_iterator as $old_state) {
$progress_bar->advance(1);
$message = sprintf(
__('Importing rack state "%s"...'),
$old_state['name']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$state = new State();
$state_fields = Sanitizer::sanitize(
[
'name' => $old_state['name'],
'states_id' => 0,
]
);
if (!($state_id = $state->getFromDBByCrit($state_fields))) {
$state_fields['comment'] = $old_state['comment'];
$state_fields['entities_id'] = $old_state['entities_id'];
$state_fields['is_recursive'] = $old_state['is_recursive'];
if (!($state_id = $state->add($state_fields))) {
$has_errors = true;
$message = sprintf(__('Unable to import rack state "%s".'), $old_state['name']);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
}
$this->addElementToMapping(
'PluginRacksRackState',
$old_state['id'],
State::class,
$state_id
);
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No rack states found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Import rooms.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importRooms()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing rooms...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$rooms_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_roomlocations',
]
);
if ($rooms_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $rooms_iterator->count());
$progress_bar->start();
foreach ($rooms_iterator as $old_room) {
$progress_bar->advance(1);
$message = sprintf(
__('Importing room "%s"...'),
$old_room['completename']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$room = new DCRoom();
$room_fields = Sanitizer::sanitize(
[
'name' => $old_room['completename'],
'entities_id' => $old_room['entities_id'],
'is_recursive' => 1,
'datacenters_id' => $this->datacenter_id,
'vis_cols' => 10,
'vis_rows' => 10,
]
);
if (
!($room_id = $room->getFromDBByCrit($room_fields))
&& !($room_id = $room->add($room_fields))
) {
$has_errors = true;
$message = sprintf(__('Unable to import room "%s".'), $old_room['completename']);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
$this->addElementToMapping(
'PluginRacksRoomLocation',
$old_room['id'],
DCRoom::class,
$room_id
);
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No rooms found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Import racks.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importRacks()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing racks...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$racks_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_racks',
]
);
if ($racks_iterator->count()) {
$i = 0;
$progress_bar = new ProgressBar($this->output, $racks_iterator->count());
$progress_bar->start();
foreach ($racks_iterator as $old_rack) {
$progress_bar->advance(1);
$message = sprintf(
__('Importing rack "%s"...'),
$old_rack['name']
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$rackmodel = $this->getCorrespondingItem(
'PluginRacksRackModel',
$old_rack['plugin_racks_rackmodels_id']
);
$racktype = $this->getCorrespondingItem(
'PluginRacksRackType',
$old_rack['plugin_racks_racktypes_id']
);
$rackstate = $this->getCorrespondingItem(
'PluginRacksRackState',
$old_rack['plugin_racks_rackstates_id']
);
$room = $this->getCorrespondingItem(
'PluginRacksRackState',
$old_rack['plugin_racks_rackstates_id']
);
if (null !== $room) {
$room_id = $room->fields['id'];
} else {
$room_id = $this->getFallbackRoomId();
if (0 == $room_id && !$this->input->getOption('skip-errors')) {
return false;
}
}
$rack = new Rack();
$rack_fields = Sanitizer::sanitize(
[
'name' => $old_rack['name'],
'comment' => "Imported from rack plugin",
'entities_id' => $old_rack['entities_id'],
'is_recursive' => $old_rack['is_recursive'],
'locations_id' => $old_rack['locations_id'],
'serial' => $old_rack['serial'],
'rackmodels_id' => null !== $rackmodel ? $rackmodel->fields['id'] : 0,
'manufacturers_id' => $old_rack['manufacturers_id'],
'racktypes_id' => null !== $racktype ? $racktype->fields['id'] : 0,
'states_id' => null !== $rackstate ? $rackstate->fields['id'] : 0,
'users_id_tech' => $old_rack['users_id_tech'],
'groups_id_tech' => $old_rack['groups_id_tech'],
'width' => (int) $old_rack['width'],
'height' => (int) $old_rack['height'],
'depth' => (int) $old_rack['depth'],
'max_weight' => (int) $old_rack['weight'],
'number_units' => $old_rack['rack_size'],
'is_template' => $old_rack['is_template'],
'template_name' => $old_rack['template_name'],
'is_deleted' => $old_rack['is_deleted'],
'dcrooms_id' => $room_id,
'bgcolor' => "#FEC95C",
]
);
if (!($rack_id = $rack->getFromDBByCrit($rack_fields))) {
$rack_fields['position'] = "9999999999999,-" . (++$i);
if (!($rack_id = $rack->add($rack_fields))) {
$has_errors = true;
$message = sprintf(__('Unable to import rack "%s".'), $old_rack['name']);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
}
$this->addElementToMapping(
'PluginRacksRack',
$old_rack['id'],
Rack::class,
$rack_id
);
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No racks found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Import rack items.
*
* @return boolean True in case of success, false in case of errors.
*/
private function importRackItems()
{
$has_errors = false;
$this->output->writeln(
'<comment>' . __('Importing rack items...') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
$items_iterator = $this->db->request(
[
'FROM' => 'glpi_plugin_racks_racks_items',
'ORDER' => 'id'
]
);
if ($items_iterator->count()) {
$progress_bar = new ProgressBar($this->output, $items_iterator->count());
$progress_bar->start();
foreach ($items_iterator as $old_item) {
$progress_bar->advance(1);
$itemtype = str_replace('Model', '', $old_item['itemtype']); // Plugin was storing model type as itemtype
$items_id = $old_item['items_id'];
$message = sprintf(
__('Importing rack item %s (%s)...'),
$itemtype,
$items_id
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERY_VERBOSE
);
$item = $this->getCorrespondingItem($itemtype, $items_id);
if (null === $item) {
$message = sprintf(__('Item %s (%s) not found.'), $itemtype, $items_id);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERBOSE
);
continue;
}
$item_input = [
'itemtype' => $item->getType(),
'items_id' => $item->fields['id'],
];
$item_rack = new Item_Rack();
if ($item_rack->getFromDBByCrit($item_input)) {
$message = sprintf(
__('Skipping item %s (%s) which is already linked to a rack.'),
$itemtype,
$items_id
);
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
OutputInterface::VERBOSITY_VERBOSE
);
continue;
}
$required_units = 1;
$modeltype = $item->getType() . 'Model';
if (class_exists($modeltype)) {
$model_fkey = getForeignKeyFieldForTable($modeltype::getTable());
if (
array_key_exists($model_fkey, $item->fields)
&& null !== ($model = $this->getCorrespondingItem($modeltype, $item->fields[$model_fkey]))
) {
$required_units = $model->fields['required_units'];
}
}
$position = $old_item['position'] - $required_units + 1;
$rack = $this->getCorrespondingItem(
'PluginRacksRack',
$old_item['plugin_racks_racks_id']
);
$item_input = $item_input + [
'racks_id' => null !== $rack ? $rack->fields['id'] : 0,
'position' => $position,
'hpos' => 0,
'bgcolor' => '#69CEBA',
'orientation' => ($old_item['faces_id'] == 1 ? Rack::FRONT : Rack::REAR),
];
if (!$item_rack->add($item_input)) {
$has_errors = true;
$message = sprintf(
__('Unable to import rack item %s (%s).'),
$itemtype,
$items_id
);
$this->outputImportError($message, $progress_bar);
if ($this->input->getOption('skip-errors')) {
continue;
} else {
return false;
}
}
}
$progress_bar->finish();
$this->output->write(PHP_EOL);
} else {
$this->output->writeln(
'<comment>' . __('No rack items found.') . '</comment>',
OutputInterface::VERBOSITY_NORMAL
);
}
return !$has_errors;
}
/**
* Add an element to mapping.
*
* @param string $old_itemtype
* @param integer $old_id
* @param string $new_itemtype
* @param integer $new_id
*
* @return void
*/
private function addElementToMapping($old_itemtype, $old_id, $new_itemtype, $new_id)
{
if (!array_key_exists($old_itemtype, $this->elements_mapping)) {
$this->elements_mapping[$old_itemtype] = [];
}
$this->elements_mapping[$old_itemtype][$old_id] = [
'itemtype' => $new_itemtype,
'id' => $new_id,
];
}
/**
* Returns item corresponding to itemtype and id.
* If item has been migrated to another itemtype, il will return the new item.
*
* @param string $itemtype
* @param integer $id
*
* @return null|CommonDBTM
*/
private function getCorrespondingItem($itemtype, $id)
{
if (
array_key_exists($itemtype, $this->elements_mapping)
&& array_key_exists($id, $this->elements_mapping[$itemtype])
) {
// Element exists in mapping, get new element
$mapping = $this->elements_mapping[$itemtype][$id];
$id = $mapping['id'];
$itemtype = $mapping['itemtype'];
}
if (!class_exists($itemtype)) {
return null;
}
$item = new $itemtype();
if (!$item->getFromDB($id)) {
return null;
}
return $item;
}
/**
* Returns fallback room id.
*
* @return number
*/
private function getFallbackRoomId()
{
if (null === $this->fallback_room_id) {
$room = new DCRoom();
$room_fields = [
'name' => 'Temp room (from plugin racks migration script)',
'entities_id' => 0,
'is_recursive' => 1,
'datacenters_id' => $this->datacenter_id,
'vis_cols' => 10,
'vis_rows' => 10,
];
if (
!($room_id = $room->getFromDBByCrit($room_fields))
&& !($room_id = $room->add($room_fields))
) {
$this->outputImportError(__('Unable to create default room.'));
$room_id = 0;
}
$this->fallback_room_id = $room_id;
}
return $this->fallback_room_id;
}
/**
* Returns verbosity level for import errors.
*
* @return number
*/
private function getImportErrorsVerbosity()
{
return $this->input->getOption('skip-errors')
? OutputInterface::VERBOSITY_NORMAL
: OutputInterface::VERBOSITY_QUIET;
}
/**
* Output import error message.
*
* @param string $message
* @param ProgressBar|null $progress_bar
*
* @return void
*/
private function outputImportError($message, ProgressBar $progress_bar = null)
{
$skip_errors = $this->input->getOption('skip-errors');
$verbosity = $skip_errors
? OutputInterface::VERBOSITY_NORMAL
: OutputInterface::VERBOSITY_QUIET;
$message = '<error>' . $message . '</error>';
if ($skip_errors && $progress_bar instanceof ProgressBar) {
$this->writelnOutputWithProgressBar(
$message,
$progress_bar,
$verbosity
);
} else {
if (!$skip_errors && $progress_bar instanceof ProgressBar) {
$this->output->write(PHP_EOL); // Keep progress bar last state and go to next line
}
$this->output->writeln(
$message,
$verbosity
);
}
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists