Skip to content
Snippets Groups Projects
Commit 18b1cd25 authored by xiaohua guan's avatar xiaohua guan Committed by Yas Naoi
Browse files

Issue #3076260 by yas, Xiaohua Guan, baldwinlouie: Switch Pods depending on namespace

parent 0f23c467
No related branches found
No related tags found
No related merge requests found
Showing
with 240 additions and 22 deletions
...@@ -71,7 +71,7 @@ display: ...@@ -71,7 +71,7 @@ display:
row_class: '' row_class: ''
default_row_class: true default_row_class: true
override: true override: true
sticky: true sticky: false
caption: '' caption: ''
summary: '' summary: ''
description: '' description: ''
...@@ -529,7 +529,48 @@ display: ...@@ -529,7 +529,48 @@ display:
entity_type: null entity_type: null
entity_field: null entity_field: null
plugin_id: entity_operations plugin_id: entity_operations
filters: { } filters:
namespace:
id: namespace
table: k8s_pod
field: namespace
relationship: none
group_type: group
admin_label: ''
operator: '='
value: ''
group: 1
exposed: true
expose:
operator_id: namespace_op
label: Namespace
description: ''
use_operator: false
operator: namespace_op
identifier: namespace
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
placeholder: ''
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
entity_type: k8s_pod
entity_field: namespace
plugin_id: string
sorts: { } sorts: { }
title: 'K8s Pods' title: 'K8s Pods'
header: { } header: { }
...@@ -584,7 +625,7 @@ display: ...@@ -584,7 +625,7 @@ display:
operator: AND operator: AND
groups: { } groups: { }
cache_metadata: cache_metadata:
max-age: -1 max-age: 0
contexts: contexts:
- 'languages:language_content' - 'languages:language_content'
- 'languages:language_interface' - 'languages:language_interface'
...@@ -601,7 +642,7 @@ display: ...@@ -601,7 +642,7 @@ display:
display_extenders: { } display_extenders: { }
path: clouds/k8s/%cloud_context/pod path: clouds/k8s/%cloud_context/pod
cache_metadata: cache_metadata:
max-age: -1 max-age: 0
contexts: contexts:
- 'languages:language_content' - 'languages:language_content'
- 'languages:language_interface' - 'languages:language_interface'
......
...@@ -57,7 +57,7 @@ function k8s_update_8203() { ...@@ -57,7 +57,7 @@ function k8s_update_8203() {
/** /**
* Add entity type k8s_pod and view k8s_pod. * Add entity type k8s_pod and view k8s_pod.
*/ */
function k8s_update_8237() { function k8s_update_8204() {
// Add entity type k8s_pod. // Add entity type k8s_pod.
$definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = \Drupal::entityTypeManager()->getDefinition('k8s_pod'); $entity_type = \Drupal::entityTypeManager()->getDefinition('k8s_pod');
...@@ -71,3 +71,14 @@ function k8s_update_8237() { ...@@ -71,3 +71,14 @@ function k8s_update_8237() {
]; ];
cloud_update_yml_definitions($files, 'k8s'); cloud_update_yml_definitions($files, 'k8s');
} }
/**
* Add namespace filter to view k8s_pod.
*/
function k8s_update_8205() {
// Update view k8s_pod.
$files = [
'views.view.k8s_pod.yml',
];
cloud_update_yml_definitions($files, 'k8s');
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\cloud\Entity\CloudConfig; use Drupal\cloud\Entity\CloudConfig;
...@@ -237,3 +238,88 @@ function k8s_views_bulk_form_submit(array $form, FormStateInterface $form_state) ...@@ -237,3 +238,88 @@ function k8s_views_bulk_form_submit(array $form, FormStateInterface $form_state)
] ]
); );
} }
/**
* Implements hook_query_TAG_Alter().
*
* Alter the query for users that can only view their own k8s namespaces.
*/
function k8s_query_k8s_pod_views_access_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('k8s_pod.namespace', $namespace_names, 'IN');
}
else {
// Add a dummy condition to make result empty.
$query->condition('k8s_pod.namespace', '');
}
}
/**
* 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 ($form['#id'] != 'views-exposed-form-k8s-pod-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']);
}
...@@ -18,6 +18,11 @@ view k8s node: ...@@ -18,6 +18,11 @@ view k8s node:
############################ ############################
# K8s Namespace # K8s Namespace
############################ ############################
# Setup permissions based on namespace
permission_callbacks:
- Drupal\k8s\K8sNamespacePermissions::configPermissions
add k8s namespace: add k8s namespace:
title: 'Add k8s namespace' title: 'Add k8s namespace'
description: 'Allow users to add k8s namespace' description: 'Allow users to add k8s namespace'
......
...@@ -22,12 +22,13 @@ class PodAccessControlHandler extends EntityAccessControlHandler { ...@@ -22,12 +22,13 @@ class PodAccessControlHandler extends EntityAccessControlHandler {
*/ */
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
$view_namespace_perm = 'view k8s namespace ' . $entity->getNamespace();
switch ($operation) { switch ($operation) {
case 'view': case 'view':
return $this->allowedIfCanAccessCloudConfig( return $this->allowedIfCanAccessCloudConfig(
$entity, $entity,
$account, $account,
'view k8s pod' [$view_namespace_perm, 'view k8s pod']
); );
case 'update': case 'update':
...@@ -35,14 +36,14 @@ class PodAccessControlHandler extends EntityAccessControlHandler { ...@@ -35,14 +36,14 @@ class PodAccessControlHandler extends EntityAccessControlHandler {
return $this->allowedIfCanAccessCloudConfig( return $this->allowedIfCanAccessCloudConfig(
$entity, $entity,
$account, $account,
'edit k8s pod' [$view_namespace_perm, 'edit k8s pod']
); );
case 'delete': case 'delete':
return $this->allowedIfCanAccessCloudConfig( return $this->allowedIfCanAccessCloudConfig(
$entity, $entity,
$account, $account,
'delete k8s pod' [$view_namespace_perm, 'delete k8s pod']
); );
} }
......
...@@ -25,6 +25,8 @@ class PodViewsData extends EntityViewsData { ...@@ -25,6 +25,8 @@ class PodViewsData extends EntityViewsData {
// Additional information for Views integration, such as table joins, can be // Additional information for Views integration, such as table joins, can be
// put here. // put here.
$data['k8s_pod']['table']['base']['access query tag'] = 'k8s_pod_views_access';
return $data; return $data;
} }
......
<?php
namespace Drupal\k8s;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides dynamic permissions for K8s namespace.
*/
class K8sNamespacePermissions implements ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs new CloudPermissions object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager) {
$this->entityTypeManager = $entityTypeManager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager')
);
}
/**
* Returns an array of cloud config permissions.
*/
public function configPermissions() {
$permissions = [];
$namespaces = $this->entityTypeManager->getStorage('k8s_namespace')->loadMultiple();
foreach ($namespaces as $namespace) {
$permissions['view k8s namespace ' . $namespace->getName()] = [
'title' => $this->t('Access entities belonging to k8s namespace %entity', ['%entity' => $namespace->getName()]),
'description' => $this->t('Allows access to entities belonging to k8s namespace %entity.', ['%entity' => $namespace->getName()]),
];
}
return $permissions;
}
}
...@@ -15,12 +15,17 @@ class PodTest extends K8sTestCase { ...@@ -15,12 +15,17 @@ class PodTest extends K8sTestCase {
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function getPermissions() { protected function getPermissions() {
$namespaces = $this->createNamespacesRandomTestFormData();
$this->createNamespaceTestEntity($namespaces[0]);
$this->namespace = $namespaces[0]['name'];
return [ return [
'list k8s pod', 'list k8s pod',
'view k8s pod', 'view k8s pod',
'edit k8s pod', 'edit k8s pod',
'add k8s pod', 'add k8s pod',
'delete k8s pod', 'delete k8s pod',
'view k8s namespace ' . $this->namespace,
]; ];
} }
...@@ -36,7 +41,7 @@ class PodTest extends K8sTestCase { ...@@ -36,7 +41,7 @@ class PodTest extends K8sTestCase {
$this->assertResponse(200); $this->assertResponse(200);
// Add a new Pod. // Add a new Pod.
$add = $this->createPodTestFormData(self::K8S_POD_REPEAT_COUNT); $add = $this->createPodTestFormData(self::K8S_POD_REPEAT_COUNT, $this->namespace);
for ($i = 0; $i < self::K8S_POD_REPEAT_COUNT; $i++) { for ($i = 0; $i < self::K8S_POD_REPEAT_COUNT; $i++) {
$this->reloadMockData(); $this->reloadMockData();
...@@ -58,7 +63,7 @@ class PodTest extends K8sTestCase { ...@@ -58,7 +63,7 @@ class PodTest extends K8sTestCase {
} }
// Edit a Pod. // Edit a Pod.
$edit = $this->createPodTestFormData(self::K8S_POD_REPEAT_COUNT); $edit = $this->createPodTestFormData(self::K8S_POD_REPEAT_COUNT, $this->namespace);
for ($i = 0; $i < self::K8S_POD_REPEAT_COUNT; $i++) { for ($i = 0; $i < self::K8S_POD_REPEAT_COUNT; $i++) {
$num = $i + 1; $num = $i + 1;
$this->updatePodMockData($edit[$i]); $this->updatePodMockData($edit[$i]);
...@@ -107,7 +112,7 @@ class PodTest extends K8sTestCase { ...@@ -107,7 +112,7 @@ class PodTest extends K8sTestCase {
$cloud_context = $this->cloudContext; $cloud_context = $this->cloudContext;
for ($i = 0; $i < self::K8S_POD_REPEAT_COUNT; $i++) { for ($i = 0; $i < self::K8S_POD_REPEAT_COUNT; $i++) {
// Create Pods. // Create Pods.
$pods = $this->createPodsRandomTestFormData(); $pods = $this->createPodsRandomTestFormData($this->namespace);
$entities = []; $entities = [];
foreach ($pods as $pod) { foreach ($pods as $pod) {
$entities[] = $this->createPodTestEntity($pod); $entities[] = $this->createPodTestEntity($pod);
......
...@@ -141,6 +141,7 @@ trait K8sTestEntityTrait { ...@@ -141,6 +141,7 @@ trait K8sTestEntityTrait {
protected function createPodTestEntity(array $pod) { protected function createPodTestEntity(array $pod) {
$entity = Pod::create([ $entity = Pod::create([
'name' => $pod['name'], 'name' => $pod['name'],
'namespace' => $pod['namespace'],
'cloud_context' => $this->cloudContext, 'cloud_context' => $this->cloudContext,
]); ]);
$entity->save(); $entity->save();
......
...@@ -112,11 +112,13 @@ trait K8sTestFormDataTrait { ...@@ -112,11 +112,13 @@ trait K8sTestFormDataTrait {
* *
* @param int $repeat_count * @param int $repeat_count
* Repeat count. * Repeat count.
* @param string $namespace
* The name of namespace.
* *
* @return array * @return array
* Test data. * Test data.
*/ */
protected function createPodTestFormData($repeat_count) { protected function createPodTestFormData($repeat_count, $namespace) {
$random = new Random(); $random = new Random();
// Input Fields. // Input Fields.
...@@ -138,7 +140,7 @@ EOS; ...@@ -138,7 +140,7 @@ EOS;
$data[] = [ $data[] = [
'name' => $name, 'name' => $name,
'post_data' => [ 'post_data' => [
'namespace' => 'namespace-' . $random->name(8, TRUE), 'namespace' => $namespace,
'detail[0][value]' => $detail, 'detail[0][value]' => $detail,
], ],
]; ];
...@@ -150,20 +152,23 @@ EOS; ...@@ -150,20 +152,23 @@ EOS;
/** /**
* Create random pods. * Create random pods.
* *
* @param string $namespace
* The name of namespace.
*
* @return array * @return array
* Random pods array. * Random pods array.
*/ */
protected function createPodsRandomTestFormData() { protected function createPodsRandomTestFormData($namespace) {
$namespaces = []; $pods = [];
$count = rand(1, 10); $count = rand(1, 10);
for ($i = 0; $i < $count; $i++) { for ($i = 0; $i < $count; $i++) {
$namespaces[] = [ $pods[] = [
'name' => sprintf('namespace-random-data #%d - %s - %s', $i + 1, date('Y/m/d H:i:s'), $this->random->name(32, TRUE)), 'name' => sprintf('namespace-random-data #%d - %s - %s', $i + 1, date('Y/m/d H:i:s'), $this->random->name(32, TRUE)),
'namespace' => 'namespace-random-data' . $this->random->name(16, TRUE), 'namespace' => $namespace,
]; ];
} }
return $namespaces; return $pods;
} }
} }
...@@ -59,8 +59,8 @@ trait AccessCheckTrait { ...@@ -59,8 +59,8 @@ trait AccessCheckTrait {
* The entity object. * The entity object.
* @param \Drupal\Core\Session\AccountInterface $account * @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account. * Run access checks for this account.
* @param string $permission * @param mixed $permissions
* The permission for the user. * The permissions for the user.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* Allowed or forbidden, neutral if tempstore is empty. * Allowed or forbidden, neutral if tempstore is empty.
...@@ -68,8 +68,11 @@ trait AccessCheckTrait { ...@@ -68,8 +68,11 @@ trait AccessCheckTrait {
protected function allowedIfCanAccessCloudConfig( protected function allowedIfCanAccessCloudConfig(
EntityInterface $entity = NULL, EntityInterface $entity = NULL,
AccountInterface $account, AccountInterface $account,
$permission $permissions
) { ) {
if (!is_array($permissions)) {
$permissions = [$permissions];
}
if ($entity == NULL) { if ($entity == NULL) {
$route = \Drupal::routeMatch(); $route = \Drupal::routeMatch();
$cloud_context = $route->getParameter('cloud_context'); $cloud_context = $route->getParameter('cloud_context');
...@@ -83,7 +86,7 @@ trait AccessCheckTrait { ...@@ -83,7 +86,7 @@ trait AccessCheckTrait {
return AccessResult::neutral(); return AccessResult::neutral();
} }
return AccessResult::allowedIfHasPermission($account, $permission); return AccessResult::allowedIfHasPermissions($account, $permissions);
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment