Loading modules/cloud_service_providers/openstack/src/Controller/ApiController.php +25 −63 Changes for modules/cloud_service_providers/openstack/src/Controller/ApiController.php: 25 added lines, 63 removed lines. Original line number Diff line number Diff line Loading @@ -12,7 +12,6 @@ use Drupal\Core\Messenger\Messenger; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountInterface; use Drupal\openstack\Entity\IntermediateFormState; use Drupal\openstack\Service\Ec2\OpenStackEc2OperationsService; use Drupal\openstack\Service\OpenStackOperationsServiceInterface; use Drupal\openstack\Service\OpenStackServiceFactoryInterface; use Drupal\views\Views; Loading Loading @@ -487,6 +486,9 @@ class ApiController extends ControllerBase implements ApiControllerInterface { * {@inheritdoc} */ public function operateEntity(Request $request, string $cloud_context, string $entity_type_id, string $entity_id, string $command): JsonResponse { // Create an instance of the entity. // The process splits between adding a new entity // and when reading an existing entity. $entity = $command !== 'create' ? $this->entityTypeManager ->getStorage($entity_type_id) Loading @@ -503,82 +505,42 @@ class ApiController extends ControllerBase implements ApiControllerInterface { ], 404); } if ($command === 'create' && $entity_type_id === 'openstack_image') { // Depending on the content of the process, // branching is performed with a switch statement. /** * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $original_entity = $entity; $form_state = new IntermediateFormState(); $method_name = ''; switch ($command . '.' . $entity_type_id) { case 'create_openstack_image': $original_entity->setName($request->get('name', '')); $original_entity->setVisibility(!empty($request->get('visibility', '')) ? 'public' : 'private'); $form_state->set('name', $request->get('name', '')); $method_name = 'createOpenStackImage'; break; $result = $this->openStackOperationsService->createOpenStackImage( $original_entity, [], $form_state ); return !empty($result) ? new JsonResponse([ 'result' => 'OK', ], 200) : new JsonResponse([ 'result' => 'NG', 'reason' => 'Internal Server Error', ], 500); } if ($command === 'delete' && $entity_type_id === 'openstack_image') { $form_state = new IntermediateFormState(); $result = $this->openStackOperationsService->deleteOpenStackImage( $entity, [], $form_state ); return !empty($result) ? new JsonResponse([ 'result' => 'OK', ], 200) : new JsonResponse([ 'result' => 'NG', 'reason' => 'Internal Server Error', ], 500); } $method_name = ''; $parameter = []; switch ($command) { case 'edit': switch ($entity_type_id) { case 'openstack_image': $method_name = 'editImage'; $parameter = [ 'name' => $request->get('name', ''), ]; $entity->setName($request->get('name', '')); $entity->setVisibility(!empty($request->get('visibility', '')) ? 'public' : 'private'); case 'edit_openstack_image': $original_entity->setName($request->get('name', '')); $original_entity->setVisibility(!empty($request->get('visibility', '')) ? 'public' : 'private'); $method_name = 'editOpenStackImage'; break; } case 'delete_openstack_image': $method_name = 'deleteOpenStackImage'; break; } $result = FALSE; if (!empty($method_name)) { $service = new OpenStackEc2OperationsService( $this->entityTypeManager, \Drupal::service('aws_cloud.ec2'), $this->cloudConfigPluginManager, $this->cloudService, $this->openStackServiceFactory, // Execute the process. $result = NULL; if (method_exists($this->openStackOperationsService, $method_name)) { $result = $this->openStackOperationsService->$method_name( $original_entity, [], $form_state ); $ec2Service = $this->openStackServiceFactory->get($cloud_context); $service->setEc2Service($ec2Service); if (method_exists($service, $method_name)) { $result = $service->$method_name($entity, $parameter); } } return !empty($result) Loading modules/cloud_service_providers/openstack/src/Form/OpenStackImageCreateForm.php +0 −13 Changes for modules/cloud_service_providers/openstack/src/Form/OpenStackImageCreateForm.php: 0 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ use Drupal\Core\Plugin\CachedDiscoveryClearerInterface; use Drupal\Core\Render\Renderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface; use Drupal\openstack\Service\OpenStackOperationsServiceInterface; use Drupal\openstack\Service\OpenStackServiceFactoryInterface; use Drupal\openstack\Service\Rest\OpenStackService as OpenStackRestService; Loading @@ -39,13 +38,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { */ protected $openStackServiceFactory; /** * The OpenStack operation service. * * @var \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface */ private $openStackEc2OperationsService; /** * The OpenStack operations Service. * Loading @@ -60,8 +52,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { * Object for interfacing with OpenStack Service. * @param \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface $ec2_service * The AWS Cloud or OpenStack EC2 Service. * @param \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface $openstack_ec2_operations_service * The OpenStack operation service. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The entity repository service. * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info Loading Loading @@ -96,7 +86,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { public function __construct( OpenStackServiceFactoryInterface $openstack_service_factory, Ec2ServiceInterface $ec2_service, OpenStackEc2OperationsServiceInterface $openstack_ec2_operations_service, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, Loading Loading @@ -133,7 +122,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { ); $this->openStackServiceFactory = $openstack_service_factory; $this->openStackEc2OperationsService = $openstack_ec2_operations_service; $this->openStackOperationsService = $openstack_operations_service; } Loading @@ -150,7 +138,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { return new static( $container->get('openstack.factory'), $container->get('openstack.ec2'), $container->get('openstack.ec2_operations'), $container->get('entity.repository'), $container->get('entity_type.bundle.info'), $container->get('datetime.time'), Loading modules/cloud_service_providers/openstack/src/Form/OpenStackImageEditForm.php +15 −22 Changes for modules/cloud_service_providers/openstack/src/Form/OpenStackImageEditForm.php: 15 added lines, 22 removed lines. Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ use Drupal\Core\Render\Renderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Drupal\cloud\Service\CloudServiceInterface; use Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface; use Drupal\openstack\Service\OpenStackOperationsServiceInterface; use Drupal\openstack\Service\OpenStackServiceFactoryInterface; use Symfony\Component\DependencyInjection\ContainerInterface; Loading @@ -39,11 +39,11 @@ class OpenStackImageEditForm extends ImageEditForm { protected $openStackServiceFactory; /** * The OpenStack operation service. * The OpenStack operations Service. * * @var \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface * @var \Drupal\openstack\Service\OpenStackOperationsServiceInterface */ private $openStackEc2OperationsService; protected $openStackOperationsService; /** * OpenStackImageEditForm constructor. Loading @@ -52,8 +52,6 @@ class OpenStackImageEditForm extends ImageEditForm { * Object for interfacing with OpenStack Service. * @param \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface $ec2_service * The AWS Cloud or OpenStack EC2 Service. * @param \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface $openstack_operations_service * The OpenStack operation service. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The entity repository service. * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info Loading Loading @@ -82,11 +80,12 @@ class OpenStackImageEditForm extends ImageEditForm { * The general renderer. * @param \Drupal\cloud\Service\CloudServiceInterface $cloud_service * The Cloud service. * @param \Drupal\openstack\Service\OpenStackOperationsServiceInterface $openstack_operations_service * The OpenStack Operations service. */ public function __construct( OpenStackServiceFactoryInterface $openstack_service_factory, Ec2ServiceInterface $ec2_service, OpenStackEc2OperationsServiceInterface $openstack_operations_service, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, Loading @@ -100,7 +99,8 @@ class OpenStackImageEditForm extends ImageEditForm { RouteMatchInterface $route_match, DateFormatterInterface $date_formatter, Renderer $renderer, CloudServiceInterface $cloud_service CloudServiceInterface $cloud_service, OpenStackOperationsServiceInterface $openstack_operations_service ) { parent::__construct( Loading @@ -122,7 +122,7 @@ class OpenStackImageEditForm extends ImageEditForm { ); $this->openStackServiceFactory = $openstack_service_factory; $this->openStackEc2OperationsService = $openstack_operations_service; $this->openStackOperationsService = $openstack_operations_service; } /** Loading @@ -138,7 +138,6 @@ class OpenStackImageEditForm extends ImageEditForm { return new static( $container->get('openstack.factory'), $container->get('openstack.ec2'), $container->get('openstack.ec2_operations'), $container->get('entity.repository'), $container->get('entity_type.bundle.info'), $container->get('datetime.time'), Loading @@ -152,7 +151,8 @@ class OpenStackImageEditForm extends ImageEditForm { $container->get('current_route_match'), $container->get('date.formatter'), $container->get('renderer'), $container->get('cloud') $container->get('cloud'), $container->get('openstack.operations') ); } Loading Loading @@ -186,9 +186,11 @@ class OpenStackImageEditForm extends ImageEditForm { '#prefix' => '<div class="container-inline">', ]; /** @var \Drupal\openstack\Entity\OpenStackImage $entity */ $entity = $this->entity; $form['image']['launch_permission']['visibility'] = [ '#type' => 'radios', '#default_value' => $this->entity->getVisibility() ? '1' : '0', '#default_value' => $entity->getVisibility() ? '1' : '0', '#options' => [ '0' => $this->t('Private'), '1' => $this->t('Public'), Loading Loading @@ -216,16 +218,7 @@ class OpenStackImageEditForm extends ImageEditForm { * The current form state. */ public function save(array $form, FormStateInterface $form_state): void { $this->copyFormItemValues($form); $this->trimTextfields($form, $form_state); $form_values = $form_state->getValues(); $visibility = array_key_exists('visibility', $form_values) ? $form_values['visibility'] : NULL; $this->openStackEc2OperationsService->editImage($this->entity, [ 'visibility' => $visibility, ]); $this->openStackOperationsService->editOpenStackImage($this->entity, $form, $form_state); } } modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsService.php +317 −0 Changes for modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsService.php: 317 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use Drupal\aws_cloud\Entity\Ec2\ImageInterface; use Drupal\aws_cloud\Service\Ec2\Ec2ServiceException; use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface; use Drupal\aws_cloud\Traits\AwsCloudEntityCheckTrait; use Drupal\cloud\Entity\CloudConfigInterface; use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManagerInterface; use Drupal\cloud\Service\CloudServiceInterface; use Drupal\cloud\Traits\CloudContentEntityTrait; Loading Loading @@ -339,6 +340,322 @@ class OpenStackOperationsService implements OpenStackOperationsServiceInterface } } /** * Copy values from #type=item elements to its original element type. * * @param array $form * The form array. */ private function copyFormItemValues(array $form): void { /** * @var \Drupal\Core\Entity\ContentEntityInterface */ $original_entity = $this->entityTypeManager ->getStorage($this->entity->getEntityTypeId()) ->load($this->entity->id()); $item_field_names = []; foreach ($form ?: [] as $name => $item) { if (!is_array($item)) { continue; } if (isset($item['#type']) && $item['#type'] === 'item' && (!isset($item['#not_field']) || $item['#not_field'] === FALSE) ) { $item_field_names[] = $name; } if (isset($item['#type']) && $item['#type'] === 'details') { foreach ($item ?: [] as $sub_item_name => $sub_item) { if (is_array($sub_item) && isset($sub_item['#type']) && $sub_item['#type'] === 'item' && (!isset($sub_item['#not_field']) || $sub_item['#not_field'] === FALSE) ) { $item_field_names[] = $sub_item_name; } } } } foreach ($item_field_names ?: [] as $item_field_name) { // Support multi-valued item fields. $values = !empty($original_entity) ? $original_entity->get($item_field_name)->getValue() : []; if (!empty($values) && count($values) > 1) { $item_field_values = array_map(static function ($value) { return $value['value']; }, $values); $this->entity->set($item_field_name, $item_field_values); } $item_field_value = !empty($original_entity) && !empty($original_entity->get($item_field_name)) ? $original_entity->get($item_field_name)->value : []; if (!empty($item_field_value)) { $this->entity->set($item_field_name, $item_field_value); } } } /** * Save a cloud content. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @throws \Drupal\Core\Entity\EntityMalformedException * @throws \Drupal\Core\Entity\EntityStorageException */ private function saveCloudContent(array $form, FormStateInterface $form_state) { /** * The entity being used by this form. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface */ $entity = $this->entity; if (!($entity instanceof CloudConfigInterface)) { $this->cloudConfigPluginManager->setCloudContext($entity->getCloudContext()); $cloud_config = $this->cloudConfigPluginManager->loadConfigEntity(); } if (!$entity->isNew() && !($entity instanceof CloudConfigInterface) && $cloud_config->isRemote()) { $status = SAVED_UPDATED; $passive_operation = 'updated remotely'; $this->processOperationStatus($entity, $passive_operation); return $status; } $status = $entity->save(); // Add a updated status message and the log. switch ($status) { case SAVED_NEW: $passive_operation = 'created'; break; case SAVED_DELETED: $passive_operation = 'deleted'; break; default: case SAVED_UPDATED: $passive_operation = 'updated'; } if (!($entity instanceof CloudConfigInterface) && $cloud_config->isRemote()) { $passive_operation .= ' remotely'; } $this->processOperationStatus($entity, $passive_operation); // Clear block and menu cache. $this->clearCacheValues($entity->getCacheTags()); return $status; } /** * Save an AWS Cloud content. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @throws \Drupal\Core\Entity\EntityMalformedException * @throws \Drupal\Core\Entity\EntityStorageException */ private function saveAwsCloudContent(array $form, FormStateInterface $form_state): void { // Copy values of the form elements whose type are item to entity. // If not, the properties corresponding to the form elements // will be saved as NULL. $this->copyFormItemValues($form); $this->trimTextfields($form, $form_state); $this->saveCloudContent($form, $form_state); } /** * Save an Image. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @throws \Drupal\Core\Entity\EntityMalformedException * @throws \Drupal\Core\Entity\EntityStorageException */ private function saveImage(array $form, FormStateInterface $form_state): void { /** * The entity being used by this form. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $entity = $this->entity; /** * The original entity data. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $original_entity = $this->entityTypeManager ->getStorage($entity->getEntityTypeId()) ->load($entity->id()); $this->saveAwsCloudContent($form, $form_state); $this->updateNameAndCreatedByTags($entity, $entity->getImageId()); $this->cloudConfigPluginManager->setCloudContext($entity->getCloudContext()); $cloud_config = $this->cloudConfigPluginManager->loadConfigEntity(); // Call 'modifyImageAttribute' // only when OwnerId is same as Account ID of Cloud Config. // It's to avoid AuthFailure error from AWS API. if ($cloud_config->get('field_account_id')->value !== $entity->getAccountId()) { return; } $form_values = $form_state->getValues(); $visibility = $form_values['visibility'] ?? 0; $permission = [ [ 'Group' => 'all', 'UserId' => $entity->getAccountId(), ], ]; // 1 => Public, 0 => Private. $launch_permission = $visibility ? ['Add' => $permission] : ['Remove' => $permission]; // Update image. $this->ec2Service->setCloudContext($entity->getCloudContext()); if (!method_exists($this->ec2Service, 'modifyImageAttribute')) { return; } // Update image description. $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'Description' => ['Value' => $entity->getDescription()], ]); // These fields (Description , LaunchPermission , or ProductCode) cannot // be specified at the same time. // See also: // https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-image-attribute.html // Update image launch permission. $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'LaunchPermission' => $launch_permission, ]); $new_account_ids = []; foreach ($entity->getLaunchPermissionAccountIds() as $account_id) { if (empty($account_id->value)) { continue; } $new_account_ids[] = $account_id->value; } $old_account_ids = []; foreach ($original_entity->getLaunchPermissionAccountIds() as $account_id) { if (empty($account_id->value)) { continue; } $old_account_ids[] = $account_id->value; } $account_ids_to_remove = array_diff($old_account_ids, $new_account_ids); $account_ids_to_add = array_diff($new_account_ids, $old_account_ids); if (!empty($account_ids_to_remove)) { $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'LaunchPermission' => [ 'Remove' => array_map(function ($item) { return ['UserId' => $item]; }, $account_ids_to_remove), ], ]); } if (!empty($account_ids_to_add)) { $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'LaunchPermission' => [ 'Add' => array_map(function ($item) { return ['UserId' => $item]; }, $account_ids_to_add), ], ]); } $this->clearCacheValues($entity->getCacheTags()); $this->dispatchSaveEvent($entity); } /** * {@inheritdoc} */ public function editOpenStackImage(ImageInterface $entity, array &$form, FormStateInterface $form_state): bool { try { $this->entity = $entity; $this->ec2Service = $this->openStackServiceFactory->get($entity->getCloudContext()); $this->saveImage($form, $form_state); /** * The entity being used by this form. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $original_entity = $entity; $visibility = !empty($original_entity->getVisibility()) ? 'public' : 'private'; // Update Image of OpenStack REST API. if ($this->ec2Service instanceof OpenStackRestService) { // Make an API call to update image. $result = $this->ec2Service->updateImage([ 'ImageId' => $original_entity->getImageId(), 'Name' => $original_entity->getName(), 'Visibility' => $visibility, ]); $old_tags = $result['Tags'] ?? []; foreach ($old_tags ?: [] as $tag) { // Delete old tags. $this->ec2Service->deleteTags( [ 'ImageId' => $original_entity->getImageId(), 'Tag' => $tag, 'EntityType' => $original_entity->getEntityTypeId(), ]); } $this->updateNameAndCreatedByTags($original_entity, $original_entity->getImageId()); } return TRUE; } catch (Ec2ServiceException $e) { $this->handleException($e); return FALSE; } } /** * Delete an Image. * Loading modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsServiceInterface.php +15 −0 Changes for modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsServiceInterface.php: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -25,6 +25,21 @@ interface OpenStackOperationsServiceInterface { */ public function createOpenStackImage(ImageInterface $entity, array &$form, FormStateInterface $form_state): bool; /** * Edit an OpenStack image. * * @param \Drupal\aws_cloud\Entity\Ec2\ImageInterface $entity * The OpenStack image entity. * @param array $form * Array of form object. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current form state. * * @return bool * TRUE when the process succeeds. */ public function editOpenStackImage(ImageInterface $entity, array &$form, FormStateInterface $form_state): bool; /** * Delete an OpenStack image. * Loading Loading
modules/cloud_service_providers/openstack/src/Controller/ApiController.php +25 −63 Changes for modules/cloud_service_providers/openstack/src/Controller/ApiController.php: 25 added lines, 63 removed lines. Original line number Diff line number Diff line Loading @@ -12,7 +12,6 @@ use Drupal\Core\Messenger\Messenger; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Session\AccountInterface; use Drupal\openstack\Entity\IntermediateFormState; use Drupal\openstack\Service\Ec2\OpenStackEc2OperationsService; use Drupal\openstack\Service\OpenStackOperationsServiceInterface; use Drupal\openstack\Service\OpenStackServiceFactoryInterface; use Drupal\views\Views; Loading Loading @@ -487,6 +486,9 @@ class ApiController extends ControllerBase implements ApiControllerInterface { * {@inheritdoc} */ public function operateEntity(Request $request, string $cloud_context, string $entity_type_id, string $entity_id, string $command): JsonResponse { // Create an instance of the entity. // The process splits between adding a new entity // and when reading an existing entity. $entity = $command !== 'create' ? $this->entityTypeManager ->getStorage($entity_type_id) Loading @@ -503,82 +505,42 @@ class ApiController extends ControllerBase implements ApiControllerInterface { ], 404); } if ($command === 'create' && $entity_type_id === 'openstack_image') { // Depending on the content of the process, // branching is performed with a switch statement. /** * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $original_entity = $entity; $form_state = new IntermediateFormState(); $method_name = ''; switch ($command . '.' . $entity_type_id) { case 'create_openstack_image': $original_entity->setName($request->get('name', '')); $original_entity->setVisibility(!empty($request->get('visibility', '')) ? 'public' : 'private'); $form_state->set('name', $request->get('name', '')); $method_name = 'createOpenStackImage'; break; $result = $this->openStackOperationsService->createOpenStackImage( $original_entity, [], $form_state ); return !empty($result) ? new JsonResponse([ 'result' => 'OK', ], 200) : new JsonResponse([ 'result' => 'NG', 'reason' => 'Internal Server Error', ], 500); } if ($command === 'delete' && $entity_type_id === 'openstack_image') { $form_state = new IntermediateFormState(); $result = $this->openStackOperationsService->deleteOpenStackImage( $entity, [], $form_state ); return !empty($result) ? new JsonResponse([ 'result' => 'OK', ], 200) : new JsonResponse([ 'result' => 'NG', 'reason' => 'Internal Server Error', ], 500); } $method_name = ''; $parameter = []; switch ($command) { case 'edit': switch ($entity_type_id) { case 'openstack_image': $method_name = 'editImage'; $parameter = [ 'name' => $request->get('name', ''), ]; $entity->setName($request->get('name', '')); $entity->setVisibility(!empty($request->get('visibility', '')) ? 'public' : 'private'); case 'edit_openstack_image': $original_entity->setName($request->get('name', '')); $original_entity->setVisibility(!empty($request->get('visibility', '')) ? 'public' : 'private'); $method_name = 'editOpenStackImage'; break; } case 'delete_openstack_image': $method_name = 'deleteOpenStackImage'; break; } $result = FALSE; if (!empty($method_name)) { $service = new OpenStackEc2OperationsService( $this->entityTypeManager, \Drupal::service('aws_cloud.ec2'), $this->cloudConfigPluginManager, $this->cloudService, $this->openStackServiceFactory, // Execute the process. $result = NULL; if (method_exists($this->openStackOperationsService, $method_name)) { $result = $this->openStackOperationsService->$method_name( $original_entity, [], $form_state ); $ec2Service = $this->openStackServiceFactory->get($cloud_context); $service->setEc2Service($ec2Service); if (method_exists($service, $method_name)) { $result = $service->$method_name($entity, $parameter); } } return !empty($result) Loading
modules/cloud_service_providers/openstack/src/Form/OpenStackImageCreateForm.php +0 −13 Changes for modules/cloud_service_providers/openstack/src/Form/OpenStackImageCreateForm.php: 0 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ use Drupal\Core\Plugin\CachedDiscoveryClearerInterface; use Drupal\Core\Render\Renderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface; use Drupal\openstack\Service\OpenStackOperationsServiceInterface; use Drupal\openstack\Service\OpenStackServiceFactoryInterface; use Drupal\openstack\Service\Rest\OpenStackService as OpenStackRestService; Loading @@ -39,13 +38,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { */ protected $openStackServiceFactory; /** * The OpenStack operation service. * * @var \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface */ private $openStackEc2OperationsService; /** * The OpenStack operations Service. * Loading @@ -60,8 +52,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { * Object for interfacing with OpenStack Service. * @param \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface $ec2_service * The AWS Cloud or OpenStack EC2 Service. * @param \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface $openstack_ec2_operations_service * The OpenStack operation service. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The entity repository service. * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info Loading Loading @@ -96,7 +86,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { public function __construct( OpenStackServiceFactoryInterface $openstack_service_factory, Ec2ServiceInterface $ec2_service, OpenStackEc2OperationsServiceInterface $openstack_ec2_operations_service, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, Loading Loading @@ -133,7 +122,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { ); $this->openStackServiceFactory = $openstack_service_factory; $this->openStackEc2OperationsService = $openstack_ec2_operations_service; $this->openStackOperationsService = $openstack_operations_service; } Loading @@ -150,7 +138,6 @@ class OpenStackImageCreateForm extends ImageCreateForm { return new static( $container->get('openstack.factory'), $container->get('openstack.ec2'), $container->get('openstack.ec2_operations'), $container->get('entity.repository'), $container->get('entity_type.bundle.info'), $container->get('datetime.time'), Loading
modules/cloud_service_providers/openstack/src/Form/OpenStackImageEditForm.php +15 −22 Changes for modules/cloud_service_providers/openstack/src/Form/OpenStackImageEditForm.php: 15 added lines, 22 removed lines. Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ use Drupal\Core\Render\Renderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; use Drupal\cloud\Service\CloudServiceInterface; use Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface; use Drupal\openstack\Service\OpenStackOperationsServiceInterface; use Drupal\openstack\Service\OpenStackServiceFactoryInterface; use Symfony\Component\DependencyInjection\ContainerInterface; Loading @@ -39,11 +39,11 @@ class OpenStackImageEditForm extends ImageEditForm { protected $openStackServiceFactory; /** * The OpenStack operation service. * The OpenStack operations Service. * * @var \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface * @var \Drupal\openstack\Service\OpenStackOperationsServiceInterface */ private $openStackEc2OperationsService; protected $openStackOperationsService; /** * OpenStackImageEditForm constructor. Loading @@ -52,8 +52,6 @@ class OpenStackImageEditForm extends ImageEditForm { * Object for interfacing with OpenStack Service. * @param \Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface $ec2_service * The AWS Cloud or OpenStack EC2 Service. * @param \Drupal\openstack\Service\Ec2\OpenStackEc2OperationsServiceInterface $openstack_operations_service * The OpenStack operation service. * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository * The entity repository service. * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info Loading Loading @@ -82,11 +80,12 @@ class OpenStackImageEditForm extends ImageEditForm { * The general renderer. * @param \Drupal\cloud\Service\CloudServiceInterface $cloud_service * The Cloud service. * @param \Drupal\openstack\Service\OpenStackOperationsServiceInterface $openstack_operations_service * The OpenStack Operations service. */ public function __construct( OpenStackServiceFactoryInterface $openstack_service_factory, Ec2ServiceInterface $ec2_service, OpenStackEc2OperationsServiceInterface $openstack_operations_service, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, Loading @@ -100,7 +99,8 @@ class OpenStackImageEditForm extends ImageEditForm { RouteMatchInterface $route_match, DateFormatterInterface $date_formatter, Renderer $renderer, CloudServiceInterface $cloud_service CloudServiceInterface $cloud_service, OpenStackOperationsServiceInterface $openstack_operations_service ) { parent::__construct( Loading @@ -122,7 +122,7 @@ class OpenStackImageEditForm extends ImageEditForm { ); $this->openStackServiceFactory = $openstack_service_factory; $this->openStackEc2OperationsService = $openstack_operations_service; $this->openStackOperationsService = $openstack_operations_service; } /** Loading @@ -138,7 +138,6 @@ class OpenStackImageEditForm extends ImageEditForm { return new static( $container->get('openstack.factory'), $container->get('openstack.ec2'), $container->get('openstack.ec2_operations'), $container->get('entity.repository'), $container->get('entity_type.bundle.info'), $container->get('datetime.time'), Loading @@ -152,7 +151,8 @@ class OpenStackImageEditForm extends ImageEditForm { $container->get('current_route_match'), $container->get('date.formatter'), $container->get('renderer'), $container->get('cloud') $container->get('cloud'), $container->get('openstack.operations') ); } Loading Loading @@ -186,9 +186,11 @@ class OpenStackImageEditForm extends ImageEditForm { '#prefix' => '<div class="container-inline">', ]; /** @var \Drupal\openstack\Entity\OpenStackImage $entity */ $entity = $this->entity; $form['image']['launch_permission']['visibility'] = [ '#type' => 'radios', '#default_value' => $this->entity->getVisibility() ? '1' : '0', '#default_value' => $entity->getVisibility() ? '1' : '0', '#options' => [ '0' => $this->t('Private'), '1' => $this->t('Public'), Loading Loading @@ -216,16 +218,7 @@ class OpenStackImageEditForm extends ImageEditForm { * The current form state. */ public function save(array $form, FormStateInterface $form_state): void { $this->copyFormItemValues($form); $this->trimTextfields($form, $form_state); $form_values = $form_state->getValues(); $visibility = array_key_exists('visibility', $form_values) ? $form_values['visibility'] : NULL; $this->openStackEc2OperationsService->editImage($this->entity, [ 'visibility' => $visibility, ]); $this->openStackOperationsService->editOpenStackImage($this->entity, $form, $form_state); } }
modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsService.php +317 −0 Changes for modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsService.php: 317 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ use Drupal\aws_cloud\Entity\Ec2\ImageInterface; use Drupal\aws_cloud\Service\Ec2\Ec2ServiceException; use Drupal\aws_cloud\Service\Ec2\Ec2ServiceInterface; use Drupal\aws_cloud\Traits\AwsCloudEntityCheckTrait; use Drupal\cloud\Entity\CloudConfigInterface; use Drupal\cloud\Plugin\cloud\config\CloudConfigPluginManagerInterface; use Drupal\cloud\Service\CloudServiceInterface; use Drupal\cloud\Traits\CloudContentEntityTrait; Loading Loading @@ -339,6 +340,322 @@ class OpenStackOperationsService implements OpenStackOperationsServiceInterface } } /** * Copy values from #type=item elements to its original element type. * * @param array $form * The form array. */ private function copyFormItemValues(array $form): void { /** * @var \Drupal\Core\Entity\ContentEntityInterface */ $original_entity = $this->entityTypeManager ->getStorage($this->entity->getEntityTypeId()) ->load($this->entity->id()); $item_field_names = []; foreach ($form ?: [] as $name => $item) { if (!is_array($item)) { continue; } if (isset($item['#type']) && $item['#type'] === 'item' && (!isset($item['#not_field']) || $item['#not_field'] === FALSE) ) { $item_field_names[] = $name; } if (isset($item['#type']) && $item['#type'] === 'details') { foreach ($item ?: [] as $sub_item_name => $sub_item) { if (is_array($sub_item) && isset($sub_item['#type']) && $sub_item['#type'] === 'item' && (!isset($sub_item['#not_field']) || $sub_item['#not_field'] === FALSE) ) { $item_field_names[] = $sub_item_name; } } } } foreach ($item_field_names ?: [] as $item_field_name) { // Support multi-valued item fields. $values = !empty($original_entity) ? $original_entity->get($item_field_name)->getValue() : []; if (!empty($values) && count($values) > 1) { $item_field_values = array_map(static function ($value) { return $value['value']; }, $values); $this->entity->set($item_field_name, $item_field_values); } $item_field_value = !empty($original_entity) && !empty($original_entity->get($item_field_name)) ? $original_entity->get($item_field_name)->value : []; if (!empty($item_field_value)) { $this->entity->set($item_field_name, $item_field_value); } } } /** * Save a cloud content. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @throws \Drupal\Core\Entity\EntityMalformedException * @throws \Drupal\Core\Entity\EntityStorageException */ private function saveCloudContent(array $form, FormStateInterface $form_state) { /** * The entity being used by this form. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface */ $entity = $this->entity; if (!($entity instanceof CloudConfigInterface)) { $this->cloudConfigPluginManager->setCloudContext($entity->getCloudContext()); $cloud_config = $this->cloudConfigPluginManager->loadConfigEntity(); } if (!$entity->isNew() && !($entity instanceof CloudConfigInterface) && $cloud_config->isRemote()) { $status = SAVED_UPDATED; $passive_operation = 'updated remotely'; $this->processOperationStatus($entity, $passive_operation); return $status; } $status = $entity->save(); // Add a updated status message and the log. switch ($status) { case SAVED_NEW: $passive_operation = 'created'; break; case SAVED_DELETED: $passive_operation = 'deleted'; break; default: case SAVED_UPDATED: $passive_operation = 'updated'; } if (!($entity instanceof CloudConfigInterface) && $cloud_config->isRemote()) { $passive_operation .= ' remotely'; } $this->processOperationStatus($entity, $passive_operation); // Clear block and menu cache. $this->clearCacheValues($entity->getCacheTags()); return $status; } /** * Save an AWS Cloud content. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @throws \Drupal\Core\Entity\EntityMalformedException * @throws \Drupal\Core\Entity\EntityStorageException */ private function saveAwsCloudContent(array $form, FormStateInterface $form_state): void { // Copy values of the form elements whose type are item to entity. // If not, the properties corresponding to the form elements // will be saved as NULL. $this->copyFormItemValues($form); $this->trimTextfields($form, $form_state); $this->saveCloudContent($form, $form_state); } /** * Save an Image. * * @param array $form * An associative array containing the structure of the form. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * * @throws \Drupal\Core\Entity\EntityMalformedException * @throws \Drupal\Core\Entity\EntityStorageException */ private function saveImage(array $form, FormStateInterface $form_state): void { /** * The entity being used by this form. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $entity = $this->entity; /** * The original entity data. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $original_entity = $this->entityTypeManager ->getStorage($entity->getEntityTypeId()) ->load($entity->id()); $this->saveAwsCloudContent($form, $form_state); $this->updateNameAndCreatedByTags($entity, $entity->getImageId()); $this->cloudConfigPluginManager->setCloudContext($entity->getCloudContext()); $cloud_config = $this->cloudConfigPluginManager->loadConfigEntity(); // Call 'modifyImageAttribute' // only when OwnerId is same as Account ID of Cloud Config. // It's to avoid AuthFailure error from AWS API. if ($cloud_config->get('field_account_id')->value !== $entity->getAccountId()) { return; } $form_values = $form_state->getValues(); $visibility = $form_values['visibility'] ?? 0; $permission = [ [ 'Group' => 'all', 'UserId' => $entity->getAccountId(), ], ]; // 1 => Public, 0 => Private. $launch_permission = $visibility ? ['Add' => $permission] : ['Remove' => $permission]; // Update image. $this->ec2Service->setCloudContext($entity->getCloudContext()); if (!method_exists($this->ec2Service, 'modifyImageAttribute')) { return; } // Update image description. $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'Description' => ['Value' => $entity->getDescription()], ]); // These fields (Description , LaunchPermission , or ProductCode) cannot // be specified at the same time. // See also: // https://docs.aws.amazon.com/cli/latest/reference/ec2/modify-image-attribute.html // Update image launch permission. $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'LaunchPermission' => $launch_permission, ]); $new_account_ids = []; foreach ($entity->getLaunchPermissionAccountIds() as $account_id) { if (empty($account_id->value)) { continue; } $new_account_ids[] = $account_id->value; } $old_account_ids = []; foreach ($original_entity->getLaunchPermissionAccountIds() as $account_id) { if (empty($account_id->value)) { continue; } $old_account_ids[] = $account_id->value; } $account_ids_to_remove = array_diff($old_account_ids, $new_account_ids); $account_ids_to_add = array_diff($new_account_ids, $old_account_ids); if (!empty($account_ids_to_remove)) { $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'LaunchPermission' => [ 'Remove' => array_map(function ($item) { return ['UserId' => $item]; }, $account_ids_to_remove), ], ]); } if (!empty($account_ids_to_add)) { $this->ec2Service->modifyImageAttribute([ 'ImageId' => $entity->getImageId(), 'LaunchPermission' => [ 'Add' => array_map(function ($item) { return ['UserId' => $item]; }, $account_ids_to_add), ], ]); } $this->clearCacheValues($entity->getCacheTags()); $this->dispatchSaveEvent($entity); } /** * {@inheritdoc} */ public function editOpenStackImage(ImageInterface $entity, array &$form, FormStateInterface $form_state): bool { try { $this->entity = $entity; $this->ec2Service = $this->openStackServiceFactory->get($entity->getCloudContext()); $this->saveImage($form, $form_state); /** * The entity being used by this form. * * @var \Drupal\aws_cloud\Entity\Ec2\ImageInterface|\Drupal\aws_cloud\Entity\Ec2\Image */ $original_entity = $entity; $visibility = !empty($original_entity->getVisibility()) ? 'public' : 'private'; // Update Image of OpenStack REST API. if ($this->ec2Service instanceof OpenStackRestService) { // Make an API call to update image. $result = $this->ec2Service->updateImage([ 'ImageId' => $original_entity->getImageId(), 'Name' => $original_entity->getName(), 'Visibility' => $visibility, ]); $old_tags = $result['Tags'] ?? []; foreach ($old_tags ?: [] as $tag) { // Delete old tags. $this->ec2Service->deleteTags( [ 'ImageId' => $original_entity->getImageId(), 'Tag' => $tag, 'EntityType' => $original_entity->getEntityTypeId(), ]); } $this->updateNameAndCreatedByTags($original_entity, $original_entity->getImageId()); } return TRUE; } catch (Ec2ServiceException $e) { $this->handleException($e); return FALSE; } } /** * Delete an Image. * Loading
modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsServiceInterface.php +15 −0 Changes for modules/cloud_service_providers/openstack/src/Service/OpenStackOperationsServiceInterface.php: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -25,6 +25,21 @@ interface OpenStackOperationsServiceInterface { */ public function createOpenStackImage(ImageInterface $entity, array &$form, FormStateInterface $form_state): bool; /** * Edit an OpenStack image. * * @param \Drupal\aws_cloud\Entity\Ec2\ImageInterface $entity * The OpenStack image entity. * @param array $form * Array of form object. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current form state. * * @return bool * TRUE when the process succeeds. */ public function editOpenStackImage(ImageInterface $entity, array &$form, FormStateInterface $form_state): bool; /** * Delete an OpenStack image. * Loading