1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 06:42:42 +01:00

Make upstream callers respect "active bindings" when querying Almanac

Summary: Ref T13641. Make "active bindings" a real query and make callers that only care about active bindings only query for active bindings.

Test Plan:
  - Queried for "bindings" and "activeBindings" via Conduit.
  - Disabled/enabled devices, saw binding status update in UI.
  - Loaded Diffusion cluster layout.
  - Grepped for `needBindings()`, `getActiveBindings()`, etc.

Subscribers: yelirekim, PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13641

Differential Revision: https://secure.phabricator.com/D21628
This commit is contained in:
epriestley 2021-03-16 13:54:11 -07:00
parent 5d64fb1815
commit 15c0c895a5
12 changed files with 192 additions and 63 deletions

View file

@ -62,6 +62,26 @@ final class AlmanacDeviceStatus
return $result; return $result;
} }
public static function getActiveStatusList() {
$results = array();
foreach (self::newDeviceStatusMap() as $status_value => $status) {
if (empty($status['disabled'])) {
$results[] = $status_value;
}
}
return $results;
}
public static function getDisabledStatusList() {
$results = array();
foreach (self::newDeviceStatusMap() as $status_value => $status) {
if (!empty($status['disabled'])) {
$results[] = $status_value;
}
}
return $results;
}
private function getDeviceStatusProperty($key, $default = null) { private function getDeviceStatusProperty($key, $default = null) {
$map = self::newDeviceStatusMap(); $map = self::newDeviceStatusMap();
$properties = idx($map, $this->getValue(), array()); $properties = idx($map, $this->getValue(), array());
@ -81,6 +101,7 @@ final class AlmanacDeviceStatus
'icon.color' => 'grey', 'icon.color' => 'grey',
'status-tag.icon' => 'fa-times', 'status-tag.icon' => 'fa-times',
'status-tag.color' => 'indigo', 'status-tag.color' => 'indigo',
'disabled' => true,
), ),
); );
} }

View file

@ -3,6 +3,17 @@
final class AlmanacBindingsSearchEngineAttachment final class AlmanacBindingsSearchEngineAttachment
extends AlmanacSearchEngineAttachment { extends AlmanacSearchEngineAttachment {
private $isActive;
public function setIsActive($is_active) {
$this->isActive = $is_active;
return $this;
}
public function getIsActive() {
return $this->isActive;
}
public function getAttachmentName() { public function getAttachmentName() {
return pht('Almanac Bindings'); return pht('Almanac Bindings');
} }
@ -13,12 +24,24 @@ final class AlmanacBindingsSearchEngineAttachment
public function willLoadAttachmentData($query, $spec) { public function willLoadAttachmentData($query, $spec) {
$query->needProperties(true); $query->needProperties(true);
$query->needBindings(true);
if ($this->getIsActive()) {
$query->needBindings(true);
} else {
$query->needActiveBindings(true);
}
} }
public function getAttachmentForObject($object, $data, $spec) { public function getAttachmentForObject($object, $data, $spec) {
$bindings = array(); $bindings = array();
foreach ($object->getBindings() as $binding) {
if ($this->getIsActive()) {
$service_bindings = $object->getActiveBindings();
} else {
$service_bindings = $object->getBindings();
}
foreach ($service_bindings as $binding) {
$bindings[] = $this->getAlmanacBindingDictionary($binding); $bindings[] = $this->getAlmanacBindingDictionary($binding);
} }

View file

@ -51,6 +51,8 @@ abstract class AlmanacSearchEngineAttachment
'phid' => $device->getPHID(), 'phid' => $device->getPHID(),
'name' => $device->getName(), 'name' => $device->getName(),
'properties' => $this->getAlmanacPropertyList($device), 'properties' => $this->getAlmanacPropertyList($device),
'status' => $device->getStatus(),
'disabled' => $device->isDisabled(),
); );
} }

View file

@ -8,6 +8,7 @@ final class AlmanacBindingQuery
private $servicePHIDs; private $servicePHIDs;
private $devicePHIDs; private $devicePHIDs;
private $interfacePHIDs; private $interfacePHIDs;
private $isActive;
public function withIDs(array $ids) { public function withIDs(array $ids) {
$this->ids = $ids; $this->ids = $ids;
@ -34,6 +35,11 @@ final class AlmanacBindingQuery
return $this; return $this;
} }
public function withIsActive($active) {
$this->isActive = $active;
return $this;
}
public function newResultObject() { public function newResultObject() {
return new AlmanacBinding(); return new AlmanacBinding();
} }
@ -95,39 +101,79 @@ final class AlmanacBindingQuery
if ($this->ids !== null) { if ($this->ids !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'id IN (%Ld)', 'binding.id IN (%Ld)',
$this->ids); $this->ids);
} }
if ($this->phids !== null) { if ($this->phids !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'phid IN (%Ls)', 'binding.phid IN (%Ls)',
$this->phids); $this->phids);
} }
if ($this->servicePHIDs !== null) { if ($this->servicePHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'servicePHID IN (%Ls)', 'binding.servicePHID IN (%Ls)',
$this->servicePHIDs); $this->servicePHIDs);
} }
if ($this->devicePHIDs !== null) { if ($this->devicePHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'devicePHID IN (%Ls)', 'binding.devicePHID IN (%Ls)',
$this->devicePHIDs); $this->devicePHIDs);
} }
if ($this->interfacePHIDs !== null) { if ($this->interfacePHIDs !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'interfacePHID IN (%Ls)', 'binding.interfacePHID IN (%Ls)',
$this->interfacePHIDs); $this->interfacePHIDs);
} }
if ($this->isActive !== null) {
if ($this->isActive) {
$where[] = qsprintf(
$conn,
'(binding.isDisabled = 0) AND (device.status IN (%Ls))',
AlmanacDeviceStatus::getActiveStatusList());
} else {
$where[] = qsprintf(
$conn,
'(binding.isDisabled = 1) OR (device.status IN (%Ls))',
AlmanacDeviceStatus::getDisabledStatusList());
}
}
return $where; return $where;
} }
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = parent::buildJoinClauseParts($conn);
if ($this->shouldJoinDeviceTable()) {
$device_table = new AlmanacDevice();
$joins[] = qsprintf(
$conn,
'JOIN %R device ON binding.devicePHID = device.phid',
$device_table);
}
return $joins;
}
private function shouldJoinDeviceTable() {
if ($this->isActive !== null) {
return true;
}
return false;
}
protected function getPrimaryTableAlias() {
return 'binding';
}
} }

View file

@ -12,6 +12,7 @@ final class AlmanacServiceQuery
private $nameSuffix; private $nameSuffix;
private $needBindings; private $needBindings;
private $needActiveBindings;
public function withIDs(array $ids) { public function withIDs(array $ids) {
$this->ids = $ids; $this->ids = $ids;
@ -59,6 +60,11 @@ final class AlmanacServiceQuery
return $this; return $this;
} }
public function needActiveBindings($need_active) {
$this->needActiveBindings = $need_active;
return $this;
}
public function newResultObject() { public function newResultObject() {
return new AlmanacService(); return new AlmanacService();
} }
@ -160,18 +166,35 @@ final class AlmanacServiceQuery
} }
protected function didFilterPage(array $services) { protected function didFilterPage(array $services) {
if ($this->needBindings) { $need_all = $this->needBindings;
$need_active = $this->needActiveBindings;
$need_any = ($need_all || $need_active);
$only_active = ($need_active && !$need_all);
if ($need_any) {
$service_phids = mpull($services, 'getPHID'); $service_phids = mpull($services, 'getPHID');
$bindings = id(new AlmanacBindingQuery())
$bindings_query = id(new AlmanacBindingQuery())
->setViewer($this->getViewer()) ->setViewer($this->getViewer())
->withServicePHIDs($service_phids) ->withServicePHIDs($service_phids)
->needProperties($this->getNeedProperties()) ->needProperties($this->getNeedProperties());
->execute();
if ($only_active) {
$bindings_query->withIsActive(true);
}
$bindings = $bindings_query->execute();
$bindings = mgroup($bindings, 'getServicePHID'); $bindings = mgroup($bindings, 'getServicePHID');
foreach ($services as $service) { foreach ($services as $service) {
$service_bindings = idx($bindings, $service->getPHID(), array()); $service_bindings = idx($bindings, $service->getPHID(), array());
$service->attachBindings($service_bindings);
if ($only_active) {
$service->attachActiveBindings($service_bindings);
} else {
$service->attachBindings($service_bindings);
}
} }
} }

View file

@ -282,6 +282,10 @@ final class AlmanacDevice
->setKey('status') ->setKey('status')
->setType('map<string, wild>') ->setType('map<string, wild>')
->setDescription(pht('Device status information.')), ->setDescription(pht('Device status information.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('disabled')
->setType('bool')
->setDescription(pht('True if device is disabled.')),
); );
} }
@ -294,6 +298,7 @@ final class AlmanacDevice
'value' => $status->getValue(), 'value' => $status->getValue(),
'name' => $status->getName(), 'name' => $status->getName(),
), ),
'disabled' => $this->isDisabled(),
); );
} }

View file

@ -21,6 +21,7 @@ final class AlmanacService
private $almanacProperties = self::ATTACHABLE; private $almanacProperties = self::ATTACHABLE;
private $bindings = self::ATTACHABLE; private $bindings = self::ATTACHABLE;
private $activeBindings = self::ATTACHABLE;
private $serviceImplementation = self::ATTACHABLE; private $serviceImplementation = self::ATTACHABLE;
public static function initializeNewService($type) { public static function initializeNewService($type) {
@ -91,23 +92,36 @@ final class AlmanacService
} }
public function getActiveBindings() { public function getActiveBindings() {
$bindings = $this->getBindings(); return $this->assertAttached($this->activeBindings);
// Filter out disabled bindings.
foreach ($bindings as $key => $binding) {
if ($binding->getIsDisabled()) {
unset($bindings[$key]);
}
}
return $bindings;
} }
public function attachBindings(array $bindings) { public function attachBindings(array $bindings) {
$active_bindings = array();
foreach ($bindings as $key => $binding) {
// Filter out disabled bindings.
if ($binding->getIsDisabled()) {
continue;
}
// Filter out bindings to disabled devices.
if ($binding->getDevice()->isDisabled()) {
continue;
}
$active_bindings[$key] = $binding;
}
$this->attachActiveBindings($active_bindings);
$this->bindings = $bindings; $this->bindings = $bindings;
return $this; return $this;
} }
public function attachActiveBindings(array $bindings) {
$this->activeBindings = $bindings;
return $this;
}
public function getServiceImplementation() { public function getServiceImplementation() {
return $this->assertAttached($this->serviceImplementation); return $this->assertAttached($this->serviceImplementation);
} }
@ -289,6 +303,9 @@ final class AlmanacService
->setAttachmentKey('properties'), ->setAttachmentKey('properties'),
id(new AlmanacBindingsSearchEngineAttachment()) id(new AlmanacBindingsSearchEngineAttachment())
->setAttachmentKey('bindings'), ->setAttachmentKey('bindings'),
id(new AlmanacBindingsSearchEngineAttachment())
->setIsActive(true)
->setAttachmentKey('activeBindings'),
); );
} }

View file

@ -56,21 +56,41 @@ final class AlmanacBindingTableView extends AphrontView {
$icon_active = id(new PHUIIconView()) $icon_active = id(new PHUIIconView())
->setIcon('fa-check') ->setIcon('fa-check')
->setColor('green')
->addSigil('has-tooltip') ->addSigil('has-tooltip')
->setMetadata( ->setMetadata(
array( array(
'tip' => pht('Active'), 'tip' => pht('Active'),
)); ));
$icon_device_disabled = id(new PHUIIconView())
->setIcon('fa-times')
->setColor('grey')
->addSigil('has-tooltip')
->setMetadata(
array(
'tip' => pht('Device Disabled'),
));
$rows = array(); $rows = array();
foreach ($bindings as $binding) { foreach ($bindings as $binding) {
$addr = $binding->getInterface()->getAddress(); $addr = $binding->getInterface()->getAddress();
$port = $binding->getInterface()->getPort(); $port = $binding->getInterface()->getPort();
$device = $binding->getDevice();
if ($device->isDisabled()) {
$binding_icon = $icon_device_disabled;
} else if ($binding->getIsDisabled()) {
$binding_icon = $icon_disabled;
} else {
$binding_icon = $icon_active;
}
$rows[] = array( $rows[] = array(
$binding->getID(), $binding->getID(),
($binding->getIsDisabled() ? $icon_disabled : $icon_active), $binding_icon,
$handles->renderHandle($binding->getServicePHID()), $handles->renderHandle($binding->getServicePHID()),
$handles->renderHandle($binding->getDevicePHID()), $handles->renderHandle($binding->getDevicePHID()),
$handles->renderHandle($binding->getInterface()->getNetworkPHID()), $handles->renderHandle($binding->getInterface()->getNetworkPHID()),
$binding->getInterface()->renderDisplayAddress(), $binding->getInterface()->renderDisplayAddress(),

View file

@ -89,7 +89,7 @@ final class DiffusionRepositoryStorageManagementPanel
AlmanacClusterRepositoryServiceType::SERVICETYPE, AlmanacClusterRepositoryServiceType::SERVICETYPE,
)) ))
->withPHIDs(array($service_phid)) ->withPHIDs(array($service_phid))
->needBindings(true) ->needActiveBindings(true)
->executeOne(); ->executeOne();
if (!$service) { if (!$service) {
// TODO: Viewer may not have permission to see the service, or it may // TODO: Viewer may not have permission to see the service, or it may
@ -104,7 +104,7 @@ final class DiffusionRepositoryStorageManagementPanel
$rows = array(); $rows = array();
if ($service) { if ($service) {
$bindings = $service->getBindings(); $bindings = $service->getActiveBindings();
$bindings = mgroup($bindings, 'getDevicePHID'); $bindings = mgroup($bindings, 'getDevicePHID');
// This is an unusual read which always comes from the master. // This is an unusual read which always comes from the master.
@ -117,29 +117,19 @@ final class DiffusionRepositoryStorageManagementPanel
$versions = mpull($versions, null, 'getDevicePHID'); $versions = mpull($versions, null, 'getDevicePHID');
// List enabled devices first, then sort devices in each group by name.
$sort = array(); $sort = array();
foreach ($bindings as $key => $binding_group) { foreach ($bindings as $key => $binding_group) {
$all_disabled = $this->isDisabledGroup($binding_group);
$sort[$key] = id(new PhutilSortVector()) $sort[$key] = id(new PhutilSortVector())
->addInt($all_disabled ? 1 : 0)
->addString(head($binding_group)->getDevice()->getName()); ->addString(head($binding_group)->getDevice()->getName());
} }
$sort = msortv($sort, 'getSelf'); $sort = msortv($sort, 'getSelf');
$bindings = array_select_keys($bindings, array_keys($sort)) + $bindings; $bindings = array_select_keys($bindings, array_keys($sort)) + $bindings;
foreach ($bindings as $binding_group) { foreach ($bindings as $binding_group) {
$all_disabled = $this->isDisabledGroup($binding_group);
$any_binding = head($binding_group); $any_binding = head($binding_group);
if ($all_disabled) { $binding_icon = 'fa-folder-open green';
$binding_icon = 'fa-times grey'; $binding_tip = pht('Active');
$binding_tip = pht('Disabled');
} else {
$binding_icon = 'fa-folder-open green';
$binding_tip = pht('Active');
}
$binding_icon = id(new PHUIIconView()) $binding_icon = id(new PHUIIconView())
->setIcon($binding_icon) ->setIcon($binding_icon)
@ -376,17 +366,4 @@ final class DiffusionRepositoryStorageManagementPanel
return $box_view; return $box_view;
} }
private function isDisabledGroup(array $binding_group) {
assert_instances_of($binding_group, 'AlmanacBinding');
foreach ($binding_group as $binding) {
if (!$binding->getIsDisabled()) {
return false;
}
}
return true;
}
} }

View file

@ -34,7 +34,7 @@ final class DrydockAlmanacServiceHostBlueprintImplementation
DrydockBlueprint $blueprint, DrydockBlueprint $blueprint,
DrydockLease $lease) { DrydockLease $lease) {
$services = $this->loadServices($blueprint); $services = $this->loadServices($blueprint);
$bindings = $this->loadAllBindings($services); $bindings = $this->getActiveBindings($services);
if (!$bindings) { if (!$bindings) {
// If there are no devices bound to the services for this blueprint, // If there are no devices bound to the services for this blueprint,
@ -222,7 +222,7 @@ final class DrydockAlmanacServiceHostBlueprintImplementation
->setViewer($viewer) ->setViewer($viewer)
->withPHIDs($service_phids) ->withPHIDs($service_phids)
->withServiceTypes($this->getAlmanacServiceTypes()) ->withServiceTypes($this->getAlmanacServiceTypes())
->needBindings(true) ->needActiveBindings(true)
->execute(); ->execute();
$services = mpull($services, null, 'getPHID'); $services = mpull($services, null, 'getPHID');
@ -242,9 +242,9 @@ final class DrydockAlmanacServiceHostBlueprintImplementation
return $this->services; return $this->services;
} }
private function loadAllBindings(array $services) { private function getActive(array $services) {
assert_instances_of($services, 'AlmanacService'); assert_instances_of($services, 'AlmanacService');
$bindings = array_mergev(mpull($services, 'getBindings')); $bindings = array_mergev(mpull($services, 'getActiveBindings'));
return mpull($bindings, null, 'getPHID'); return mpull($bindings, null, 'getPHID');
} }
@ -271,15 +271,10 @@ final class DrydockAlmanacServiceHostBlueprintImplementation
$allocated_phids = array_fuse($allocated_phids); $allocated_phids = array_fuse($allocated_phids);
$services = $this->loadServices($blueprint); $services = $this->loadServices($blueprint);
$bindings = $this->loadAllBindings($services); $bindings = $this->getActiveBindings($services);
$free = array(); $free = array();
foreach ($bindings as $binding) { foreach ($bindings as $binding) {
// Don't consider disabled bindings to be available.
if ($binding->getIsDisabled()) {
continue;
}
if (empty($allocated_phids[$binding->getPHID()])) { if (empty($allocated_phids[$binding->getPHID()])) {
$free[] = $binding; $free[] = $binding;
} }

View file

@ -61,7 +61,7 @@ final class PhabricatorRepositoryManagementClusterizeWorkflow
array( array(
AlmanacClusterRepositoryServiceType::SERVICETYPE, AlmanacClusterRepositoryServiceType::SERVICETYPE,
)) ))
->needBindings(true) ->needActiveBindings(true)
->executeOne(); ->executeOne();
if (!$service) { if (!$service) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(

View file

@ -2109,7 +2109,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
throw new Exception( throw new Exception(
pht( pht(
'The Almanac service for this repository is not bound to any '. 'The Almanac service for this repository is not bound to any '.
'interfaces.')); 'active interfaces.'));
} }
$uris = array(); $uris = array();
@ -2531,7 +2531,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
$service = id(new AlmanacServiceQuery()) $service = id(new AlmanacServiceQuery())
->setViewer(PhabricatorUser::getOmnipotentUser()) ->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($service_phid)) ->withPHIDs(array($service_phid))
->needBindings(true) ->needActiveBindings(true)
->needProperties(true) ->needProperties(true)
->executeOne(); ->executeOne();
if (!$service) { if (!$service) {