cloud-8.x-2.0-beta1/modules/cloud_service_providers/k8s/k8s.module

modules/cloud_service_providers/k8s/k8s.module
<?php

/**
 * @file
 * K8s module.
 *
 * This module handles UI interactions with the cloud system for K8s.
 */

use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Component\Serialization\Yaml;
use Drupal\field\Entity\FieldStorageConfig;

use Drupal\cloud\Entity\CloudConfig;
use Drupal\k8s\Entity\K8sNamespace;
use Drupal\k8s\Service\K8sServiceException;
use Drupal\Core\Entity\EntityTypeInterface;

/**
 * Implements hook_cloud_config_update().
 */
function k8s_cloud_config_update(CloudConfig $cloud_config) {
  if ($cloud_config->bundle() == 'k8s') {
    // Update resources.
    k8s_update_resources($cloud_config->getCloudContext());
  }
}

/**
 * Implements hook_cloud_config_delete().
 */
function k8s_cloud_config_delete(CloudConfig $cloud_config) {
  if ($cloud_config->bundle() == 'k8s') {
    /* @var \Drupal\k8s\Service\K8sServiceInterface $k8s_service */
    $k8s_service = \Drupal::service('k8s');
    $k8s_service->setCloudContext($cloud_config->getCloudContext());
    $k8s_service->clearAllEntities();
  }
}

/**
 * Update resources.
 *
 * @param string $cloud_context
 *   The cloud service provider entities.
 */
function k8s_update_resources($cloud_context) {
  $k8s_service = \Drupal::service('k8s');
  $k8s_service->setCloudContext($cloud_context);
  $k8s_service->updateNodes();
  $k8s_service->updateNamespaces();
  $k8s_service->updatePods();
  $k8s_service->updateDeployments();
  $k8s_service->updateReplicaSets();
  $k8s_service->updateServices();
  $k8s_service->updateCronJobs();
  $k8s_service->updateJobs();
  $k8s_service->updateResourceQuotas();
  $k8s_service->updateLimitRanges();
  $k8s_service->updateSecrets();
  $k8s_service->updateConfigMaps();
  $k8s_service->updateNetworkPolicies();
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Alter cloud service provider k8s edit form.
 */
function k8s_form_cloud_config_k8s_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  k8s_form_cloud_config_k8s_form_common_alter($form, $form_state, $form_id);
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Alter cloud service provider k8s add form.
 */
function k8s_form_cloud_config_k8s_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['cloud_context']['#access'] = FALSE;
  $form['field_location_country']['#access'] = FALSE;
  $form['field_location_city']['#access'] = FALSE;
  $form['field_location_longitude']['#access'] = FALSE;
  $form['field_location_latitude']['#access'] = FALSE;

  $form['actions']['submit']['#submit'] = ['k8s_form_cloud_config_k8s_add_form_submit'];
  $form['#validate'][] = 'k8s_form_cloud_config_k8s_add_form_validate';

  k8s_form_cloud_config_k8s_form_common_alter($form, $form_state, $form_id);

  // Location fieldset is unnecessary for add form.
  unset($form['location']);
}

/**
 * Validate function for form cloud_config_k8s_add_form.
 *
 * @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.
 */
function k8s_form_cloud_config_k8s_add_form_validate(array &$form, FormStateInterface $form_state) {

  // Validate Name.
  $name = $form_state->getValue('name')[0]['value'];
  $cloud_context = k8s_form_cloud_config_k8s_add_form_create_cloud_context($name);

  $entities = \Drupal::service('plugin.manager.cloud_config_plugin')->loadConfigEntities('k8s');
  $cloud_contexts_exist = array_map(function ($entity) {
    return $entity->getCloudContext();
  }, $entities);

  if (in_array($cloud_context, $cloud_contexts_exist)) {
    $form_state->setErrorByName(
      'name',
      t('The cloud service providers have existed with the same cloud context.')
    );
  }

  // Validate API server.
  if (empty($form_state->getValue('field_api_server')[0]['value'])) {
    $form_state->setErrorByName(
      'field_api_server',
      t('The API server field cannot be empty.')
    );
  }

  // Validate Token.
  if (empty($form_state->getValue('field_token')[0]['value'])) {
    $form_state->setErrorByName(
      'field_token',
      t('The token field cannot be empty.')
    );
  }
}

/**
 * Create cloud context according to name.
 *
 * @param string $name
 *   The name of the cloud service provider (CloudConfig) entity.
 *
 * @return string
 *   The cloud context
 */
function k8s_form_cloud_config_k8s_add_form_create_cloud_context($name) {

  // Convert ' ' or '-' to '_'.
  $cloud_context = preg_replace('/[ \-]/', '_', strtolower($name));

  // Remove special characters.
  $cloud_context = preg_replace('/[^a-z0-9_]/', '', $cloud_context);

  return $cloud_context;
}

/**
 * Submit function for form cloud_config_k8s_add_form.
 *
 * @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.
 */
function k8s_form_cloud_config_k8s_add_form_submit(array $form, FormStateInterface $form_state) {
  // Create CloudConfig.
  $entity = CloudConfig::create([
    'type' => 'k8s',
  ]);

  $entity_object = $form_state->getFormObject()->getEntity();
  $field_names = array_keys($entity_object->getFields());

  $form_values = $form_state->getValues();
  foreach ($form_values as $key => $value) {
    if (in_array($key, $field_names)) {
      $entity->set($key, $value);
    }
  }

  // Set cloud_context.
  $name = $form_state->getValue('name')[0]['value'];
  $cloud_context = k8s_form_cloud_config_k8s_add_form_create_cloud_context($name);
  $entity->setCloudContext($cloud_context);
  $entity->save();

  \Drupal::messenger()->addMessage(
    t('Created the cloud service provider: @name.', [
      '@name' => $name,
    ])
  );

  k8s_update_resources($cloud_context);

  // Rebuild menu.
  \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();

  $form_state->setRedirect('entity.cloud_config.collection', []);
}

/**
 * Common alter function.
 *
 * Common alter function for k8s_form_cloud_config_k8s_edit_form and
 * k8s_form_cloud_config_k8s_add_form.
 */
function k8s_form_cloud_config_k8s_form_common_alter(&$form, FormStateInterface $form_state, $form_id) {
  k8s_cloud_config_fieldsets($form);

  $form['new_revision']['#access'] = FALSE;
  $form['revision_log_message']['#access'] = FALSE;
}

/**
 * Implements hook_form_alter().
 */
function k8s_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'views_form_k8s_') === 0) {
    $form['#submit'][] = 'k8s_views_bulk_form_submit';
  }
}

/**
 * Submit function for form views_form_k8s_*.
 *
 * @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.
 */
function k8s_views_bulk_form_submit(array $form, FormStateInterface $form_state) {

  $request = \Drupal::service('request_stack')->getCurrentRequest();

  $action = $form_state->getValue('action');

  // Get entity_type and operation name.
  // $action - Format: '<entity_type>_<operation>_action'.
  preg_match('/^(.+)_(.+)_action/', $action, $matches);
  $entity_type = $matches[1];
  $operation = $matches[2];

  // Change the confirm form.
  // Format: 'entity.<entity_type>.<operation>_multiple_form'.
  $form_state->setRedirect(
    "entity.${entity_type}.${operation}_multiple_form", [
      'cloud_context' => $request->get('cloud_context'),
    ]
  );
}

/**
 * Implements hook_query_TAG_Alter().
 *
 * Alter the query for users that can only view their own k8s namespaces.
 */
function k8s_query_k8s_entity_views_access_with_namespace_alter(AlterableInterface $query) {
  if (!$account = $query->getMetaData('account')) {
    $account = \Drupal::currentUser();
  }

  $route = \Drupal::routeMatch();
  $cloud_context = $route->getParameter('cloud_context');

  $entity_storage = \Drupal::entityTypeManager()->getStorage('k8s_namespace');
  $entity_ids = $entity_storage
    ->getQuery()
    ->condition('cloud_context', $cloud_context)
    ->execute();
  $namespaces = $entity_storage->loadMultiple($entity_ids);

  $namespace_names = [];
  foreach ($namespaces as $namespace) {
    if ($account->hasPermission('view k8s namespace ' . $namespace->getName())) {
      $namespace_names[] = $namespace->getName();
    }
  }

  // Add a namespace condition.
  if (!empty($namespace_names)) {
    $query->condition('namespace', $namespace_names, 'IN');
  }
  else {
    // Add a dummy condition to make result empty.
    $query->condition('namespace', '');
  }

  // Add owner condition for pod.
  if ($route->getRouteName() == 'view.k8s_pod.list') {
    if ($account->hasPermission('view any k8s pod')) {
      return;
    }
    else {
      // Add a uid condition.
      $query->condition('k8s_pod.uid', $account->id());
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Alters the artist options on Pod listing view.
 */
function k8s_form_views_exposed_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // If not the view we are looking, move on.
  if (!in_array($form['#id'], [
    'views-exposed-form-k8s-pod-list',
    'views-exposed-form-k8s-deployment-list',
    'views-exposed-form-k8s-replica-set-list',
    'views-exposed-form-k8s-service-list',
    'views-exposed-form-k8s-cron-job-list',
    'views-exposed-form-k8s-job-list',
    'views-exposed-form-k8s-resource-quota-list',
    'views-exposed-form-k8s-limit-range-list',
    'views-exposed-form-k8s-secret-list',
    'views-exposed-form-k8s-config-map-list',
    'views-exposed-form-k8s-network-policy-list',
  ])) {
    return FALSE;
  }

  // Query namespaces.
  $storage = Drupal::getContainer()->get('entity_type.manager')->getStorage('k8s_namespace');

  // Gather namespaces sort by title.
  $namespace_ids = $storage->getQuery()
    ->sort('name')
    ->execute();

  // If there are no namespaces, move on.
  if (!$namespace_ids) {
    return FALSE;
  }

  // Start building out the options for our select list.
  $options = [];
  $namespaces = $storage->loadMultiple($namespace_ids);

  // Push titles into select list.
  foreach ($namespaces as $namespace) {
    $options[$namespace->getName()] = $namespace->getName();
  }

  // Start building out our new form element.
  $namespace_field = 'namespace';
  $form[$namespace_field]['#type'] = 'select';
  $form[$namespace_field]['#multiple'] = FALSE;

  // Specify the empty option for our select list.
  $form[$namespace_field]['#empty_option'] = t('- Any -');

  // Add the $options from above to our select list.
  $form[$namespace_field]['#options'] = $options;
  $form[$namespace_field]['#weight'] = -50;
  unset($form[$namespace_field]['#size']);
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 */
function k8s_k8s_namespace_delete(K8sNamespace $namespace) {
  k8s_clear_cache();
}

/**
 * Clear cache.
 */
function k8s_clear_cache() {
  \Drupal::cache('menu')->invalidateAll();
  \Drupal::service('cache.render')->deleteAll();
  \Drupal::service('router.builder')->rebuild();
  \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();
}

/**
 * Set allowed values for the field_namespace.
 *
 * @param \Drupal\field\Entity\FieldStorageConfig $definition
 *   The field definition.
 * @param \Drupal\Core\Entity\ContentEntityInterface|null $entity
 *   The entity being created if applicable.
 * @param bool $cacheable
 *   Boolean indicating if the results are cacheable.
 *
 * @return array
 *   An array of possible key and value options.
 *
 * @see options_allowed_values()
 */
function k8s_namespace_allowed_values_function(FieldStorageConfig $definition, ContentEntityInterface $entity = NULL, $cacheable) {
  $options = [];

  $route = \Drupal::routeMatch();
  $cloud_context = $route->getParameter('cloud_context');

  $k8s_service = \Drupal::service('k8s');
  $k8s_service->setCloudContext($cloud_context);

  $namespaces = $k8s_service->getNamespaces();

  foreach ($namespaces as $namespace) {
    $name = $namespace['metadata']['name'];
    $options[$name] = $name;
  }
  return $options;
}

/**
 * Set allowed values for the field_object.
 *
 * @param \Drupal\field\Entity\FieldStorageConfig $definition
 *   The field definition.
 * @param \Drupal\Core\Entity\ContentEntityInterface|null $entity
 *   The entity being created if applicable.
 * @param bool $cacheable
 *   Boolean indicating if the results are cacheable.
 *
 * @return array
 *   An array of possible key and value options.
 *
 * @see options_allowed_values()
 */
function k8s_object_allowed_values_function(FieldStorageConfig $definition, ContentEntityInterface $entity = NULL, $cacheable) {
  return k8s_supported_cloud_server_templates();
}

/**
 * Defines the supported cloud server template types.
 *
 * @return array
 *   An array of supported templates.
 */
function k8s_supported_cloud_server_templates() {
  return [
    'deployment' => 'Deployment',
    'pod' => 'Pod',
  ];
}

/**
 * Implements hook_entity_view_alter().
 */
function k8s_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  if ($entity->getEntityTypeId() == 'cloud_server_template'
    && $entity->bundle() == 'k8s'
  ) {
    cloud_form_reorder($build, k8s_server_template_field_orders(FALSE));
  }

  if (in_array($entity->getEntityTypeId(), ['k8s_node', 'k8s_pod'])) {

    // Confirm whether the metrics API can be used or not.
    $metrics_enabled = TRUE;
    $k8s_service = \Drupal::service('k8s');
    if (!empty($entity->getCloudContext())) {
      $k8s_service->setCloudContext($entity->getCloudContext());
      try {
        $k8s_service->getMetricsNodes();
      }
      catch (K8sServiceException $e) {
        $metrics_enabled = FALSE;
      }
    }

    if (isset($build['entity_metrics'])) {

      $build['entity_metrics']['k8s_entity_metrics'] = [
        '#markup' => '<div id="k8s_entity_metrics"></div>',
      ];

      $build['#attached']['library'][] = 'k8s/k8s_entity_metrics';
    }

    if (isset($build['node_allocated_resources'])) {

      $build['node_allocated_resources']['k8s_node_allocated_resources'] = [
        '#markup' => '<div id="k8s_node_allocated_resources"></div>',
      ];

      $build['#attached']['library'][] = 'k8s/k8s_node_allocated_resources';
    }

    if (isset($build['node_heatmap'])) {

      $build['node_heatmap']['k8s_node_heatmap'] = [
        '#markup' => '<div id="k8s_node_heatmap"></div>',
      ];

      $build['#attached']['library'][] = 'k8s/k8s_node_heatmap';
    }

    $build['#attached']['drupalSettings']['k8s']['metrics_enable'] = $metrics_enabled;
    $config = \Drupal::config('k8s.settings');
    $build['#attached']['drupalSettings']['k8s']['k8s_js_refresh_interval']
      = $config->get('k8s_js_refresh_interval');
  }

  if (isset($build['node_pods'])) {

    $build['node_pods']['k8s_node_pods'] = [
      '#type' => 'view',
      '#name' => 'k8s_pod',
      '#display_id' => 'block_for_node',
    ];

  }

}

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function k8s_cloud_server_template_presave(EntityInterface $entity) {
  if ($entity->bundle() == 'k8s') {
    $yaml = Yaml::decode($entity->field_detail->value);
    $kind = $yaml['kind'];
    if (isset($kind)) {
      $templates = k8s_supported_cloud_server_templates();
      $object = array_search($kind, $templates);
      if ($object != FALSE) {
        $entity->field_object->value = $object;
      }
    }
  }
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function k8s_form_cloud_server_template_k8s_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['field_object']['#access'] = FALSE;
  k8s_form_cloud_server_template_k8s_form_common_alter($form, $form_state, $form_id);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function k8s_form_cloud_server_template_k8s_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['field_object']['#access'] = FALSE;
  k8s_form_cloud_server_template_k8s_form_common_alter($form, $form_state, $form_id);
  // Hide new revision checkbox.
  $form['new_revision']['#access'] = FALSE;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function k8s_form_cloud_server_template_k8s_copy_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['field_object']['#access'] = FALSE;
  k8s_form_cloud_server_template_k8s_form_common_alter($form, $form_state, $form_id);

  $name = $form['pod']['name']['widget'][0]['value']['#default_value'];
  $form['pod']['name']['widget'][0]['value']['#default_value'] = t('copy_of_@name',
    [
      '@name' => $name,
    ]);

  // Hide new revision checkbox.
  $form['new_revision']['#access'] = FALSE;

  // Clear the revision log message.
  $form['others']['revision_log_message']['widget'][0]['value']['#default_value'] = NULL;

  // Change value of the submit button.
  $form['actions']['submit']['#value'] = t('Copy');

  // Delete the delete button.
  $form['actions']['delete']['#access'] = FALSE;

  $form['actions']['submit']['#submit'][1] = 'k8s_form_cloud_server_template_k8s_copy_form_submit';

}

/**
 * Submit function for k8s server template copy.
 *
 * @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.
 */
function k8s_form_cloud_server_template_k8s_copy_form_submit(array $form, FormStateInterface $form_state) {
  $server_template = $form_state
    ->getFormObject()
    ->getEntity();

  $server_template = $server_template->createDuplicate();
  if ($server_template->save()) {
    \Drupal::messenger()->addMessage(
      t('Created the @name cloud server template', [
        '@name' => $server_template->getName(),
      ])
    );

    $form_state->setRedirect(
      'entity.cloud_server_template.canonical',
      [
        'cloud_context' => $server_template->getCloudContext(),
        'cloud_server_template' => $server_template->id(),
      ]
    );
  }
  else {
    \Drupal::messenger()->addError(
      t("The cloud server template @name couldn't create.", [
        '@name' => $server_template->getName(),
      ])
    );
  }
}

/**
 * Validate function for form cloud_server_template_k8s_copy_form.
 *
 * @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.
 */
function k8s_cloud_form_cloud_server_template_k8s_form_validate(array &$form, FormStateInterface $form_state) {
  $form_object = $form_state->getFormObject();
  $server_template = $form_object->getEntity();
  $server_template->setName($form_state->getValue('copy_server_template_name'));
  $violations = $server_template->validate();
  foreach ($violations->getByField('name') as $violation) {
    $form_state->setErrorByName('copy_server_template_name', $violation->getMessage());
  }
}

/**
 * Common alter function for edit and add forms.
 */
function k8s_form_cloud_server_template_k8s_form_common_alter(&$form, FormStateInterface $form_state, $form_id) {
  cloud_form_reorder($form, k8s_server_template_field_orders());
}

/**
 * Return orders of k8s cloud server template fields.
 *
 * @param bool $include_name
 *   Whether to include name field or not.
 *
 * @return array
 *   Fieldsets array.
 */
function k8s_server_template_field_orders($include_name = TRUE) {
  $fieldsets_def = [
    [
      'name' => 'k8s',
      'title' => t('K8s'),
      'open' => TRUE,
      'fields' => [
        'name',
        'field_namespace',
        'field_object',
        'field_detail',
      ],
    ],
    [
      'name' => 'others',
      'title' => t('Others'),
      'open' => FALSE,
      'fields' => [
        'revision_log_message',
        'cloud_context',
        'uid',
      ],
    ],
  ];

  if (!$include_name) {
    unset($fieldsets_def[0]['fields'][0]);
  }

  return $fieldsets_def;
}

/**
 * Implements hook_entity_bundle_field_info_alter().
 */
function k8s_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  if ($bundle === 'k8s') {
    if (isset($fields['field_detail'])) {
      // Use the ID as defined in the annotation of the constraint definition.
      $fields['field_detail']->addConstraint('yaml_array_data', []);
      $fields['field_detail']->addConstraint('yaml_object_support', []);
    }
  }
}

/**
 * Implements hook_cron().
 */
function k8s_cron() {
  // Write metrics to log.
  $config_entities = \Drupal::service('plugin.manager.cloud_config_plugin')
    ->loadConfigEntities('k8s');
  $k8s_service = \Drupal::service('k8s');
  foreach ($config_entities as $config_entity) {
    try {
      $k8s_service->setCloudContext($config_entity->getCloudContext());
      $metrics_nodes = $k8s_service->getMetricsNodes();
      k8s_export_node_metrics($config_entity->getCloudContext(), $metrics_nodes);

      $metrics_pods = $k8s_service->getMetricsPods();
      k8s_export_pod_metrics($config_entity->getCloudContext(), $metrics_pods);
    }
    catch (\Exception $e) {
      \Drupal::logger('k8s_cron')->debug($e->getMessage());
    }
  }
}

/**
 * Export node metrics to log.
 *
 * @param string $cloud_context
 *   The cloud context.
 * @param array $metrics_nodes
 *   The metrics of nodes.
 */
function k8s_export_node_metrics($cloud_context, array $metrics_nodes) {
  $metrics = [];
  foreach ($metrics_nodes as $metrics_node) {
    $node_name = $metrics_node['metadata']['name'];
    $cpu = k8s_convert_cpu_to_float($metrics_node['usage']['cpu']);
    $memory = k8s_convert_memory_to_integer($metrics_node['usage']['memory']);
    $metrics[$cloud_context]['nodes'][$node_name] = [
      'cpu' => $cpu,
      'memory' => $memory,
    ];
  }

  \Drupal::logger('k8s_metrics')->info((Yaml::encode($metrics)));
}

/**
 * Export pod metrics to log.
 *
 * @param string $cloud_context
 *   The cloud context.
 * @param array $metrics_pods
 *   The metrics of nodes.
 */
function k8s_export_pod_metrics($cloud_context, array $metrics_pods) {
  $metrics = [];
  foreach ($metrics_pods as $metrics_pod) {
    $pod_namespace = $metrics_pod['metadata']['namespace'];
    $pod_name = $metrics_pod['metadata']['name'];

    $cpu = 0;
    $memory = 0;
    foreach ($metrics_pod['containers'] as $container) {
      $cpu += k8s_convert_cpu_to_float($container['usage']['cpu']);
      $memory += k8s_convert_memory_to_integer($container['usage']['memory']);

    }

    $metrics[$cloud_context]['pods']["$pod_namespace:$pod_name"] = [
      'cpu' => $cpu,
      'memory' => $memory,
    ];
  }

  \Drupal::logger('k8s_metrics')->info((Yaml::encode($metrics)));
}

/**
 * Convert the value of CPU to float value.
 *
 * @param string $cpu
 *   The string value of CPU.
 *
 * @return float
 *   The value converted.
 */
function k8s_convert_cpu_to_float($cpu) {
  $type = substr($cpu, -1);
  if ($type == 'm') {
    return floatval(substr($cpu, 0, strlen($cpu) - 1)) / 1000;
  }

  if ($type == 'n') {
    return floatval(substr($cpu, 0, strlen($cpu) - 1)) / 1000000000;
  }

  return floatval($cpu);
}

/**
 * Convert the value of memory to integer value.
 *
 * @param string $memory
 *   The string value of memory.
 *
 * @return int
 *   The value converted.
 */
function k8s_convert_memory_to_integer($memory) {
  $decimal_units = [
    'k', 'm', 'g', 't', 'p', 'e',
  ];

  $binary_units = [
    'ki', 'mi', 'gi', 'ti', 'pi', 'ei',
  ];

  $memory = strtolower($memory);
  $unit = substr($memory, -1);
  $pos = array_search($unit, $decimal_units);
  if ($pos !== FALSE) {
    $number = intval(substr($memory, 0, strlen($memory) - 1));
    return $number * pow(1000, $pos + 1);
  }

  $unit = substr($memory, -2);
  $pos = array_search($unit, $binary_units);
  if ($pos !== FALSE) {
    $number = intval(substr($memory, 0, strlen($memory) - 2));

    return $number * pow(1024, $pos + 1);
  }

  return 0;
}

/**
 * Format memory string.
 *
 * @param float $number
 *   The number of memory size.
 *
 * @return string
 *   The formatted memory string.
 */
function k8s_format_memory($number) {
  $binary_units = [
    'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei',
  ];

  $exp = 1;
  $memory_unit = '';
  $memory_number = $number;
  foreach ($binary_units as $unit) {
    $base_number = pow(1024, $exp++);
    if ($number < $base_number) {
      break;
    }

    $memory_number = round($number / $base_number, 2);
    $memory_unit = $unit;
  }

  return $memory_number . $memory_unit;
}

/**
 * Get fieldsets of cloud config page.
 *
 * @param array $fields
 *   Array of fields.
 */
function k8s_cloud_config_fieldsets(array &$fields) {
  $fieldset_defs = [
      [
        'name' => 'cloud_provider',
        'title' => t('Cloud Service Provider'),
        'open' => TRUE,
        'fields' => [
          'cloud_context',
          'name',
        ],
      ],
      [
        'name' => 'credentials',
        'title' => t('Credentials'),
        'open' => TRUE,
        'fields' => [
          'field_api_server',
          'field_token',
        ],
      ],
      [
        'name' => 'location',
        'title' => t('Location'),
        'open' => TRUE,
        'fields' => [
          'cloud_config_location_map',
          'field_location_country',
          'field_location_city',
          'field_location_latitude',
          'field_location_longitude',
        ],
      ],
  ];

  $others = [
    'name' => 'others',
    'title' => t('Others'),
    'open' => FALSE,
    'fields' => [
      'uid',
    ],
  ];

  $fieldset_defs[] = $others;

  cloud_form_reorder($fields, $fieldset_defs);
}

/**
 * Implements hook_ENTITY_TYPE_view_alter().
 */
function k8s_cloud_config_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  if ($entity->bundle() == 'k8s') {
    $map_json_url = \Drupal::config('cloud.settings')->get('cloud_location_map_json_url');
    $url = Url::fromRoute('entity.cloud_config.location', ['cloud_config' => $entity->id()])->toString();

    $build['cloud_config_location_map'] = [
      '#markup' => '<div id="cloud_config_location"></div>',
      '#attached' => [
        'library' => [
          'cloud/cloud_config_location',
        ],
        'drupalSettings' => [
          'cloud' => [
            'cloud_location_map_json_url' => $map_json_url,
            'cloud_config_location_json_url' => $url,
          ],
        ],
      ],
    ];

    $build['field_location_country']['#access'] = FALSE;
    $build['field_location_city']['#access'] = FALSE;
    $build['field_location_longitude']['#access'] = FALSE;
    $build['field_location_latitude']['#access'] = FALSE;

    k8s_cloud_config_fieldsets($build);

  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc