Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/drydock/storage/DrydockResource.php
12256 views
1
<?php
2
3
final class DrydockResource extends DrydockDAO
4
implements
5
PhabricatorPolicyInterface,
6
PhabricatorConduitResultInterface {
7
8
protected $id;
9
protected $phid;
10
protected $blueprintPHID;
11
protected $status;
12
protected $until;
13
protected $type;
14
protected $attributes = array();
15
protected $capabilities = array();
16
protected $ownerPHID;
17
18
private $blueprint = self::ATTACHABLE;
19
private $unconsumedCommands = self::ATTACHABLE;
20
21
private $isAllocated = false;
22
private $isActivated = false;
23
private $activateWhenAllocated = false;
24
private $slotLocks = array();
25
26
protected function getConfiguration() {
27
return array(
28
self::CONFIG_AUX_PHID => true,
29
self::CONFIG_SERIALIZATION => array(
30
'attributes' => self::SERIALIZATION_JSON,
31
'capabilities' => self::SERIALIZATION_JSON,
32
),
33
self::CONFIG_COLUMN_SCHEMA => array(
34
'ownerPHID' => 'phid?',
35
'status' => 'text32',
36
'type' => 'text64',
37
'until' => 'epoch?',
38
),
39
self::CONFIG_KEY_SCHEMA => array(
40
'key_type' => array(
41
'columns' => array('type', 'status'),
42
),
43
'key_blueprint' => array(
44
'columns' => array('blueprintPHID', 'status'),
45
),
46
),
47
) + parent::getConfiguration();
48
}
49
50
public function generatePHID() {
51
return PhabricatorPHID::generateNewPHID(DrydockResourcePHIDType::TYPECONST);
52
}
53
54
public function getResourceName() {
55
return $this->getBlueprint()->getResourceName($this);
56
}
57
58
public function getAttribute($key, $default = null) {
59
return idx($this->attributes, $key, $default);
60
}
61
62
public function getAttributesForTypeSpec(array $attribute_names) {
63
return array_select_keys($this->attributes, $attribute_names);
64
}
65
66
public function setAttribute($key, $value) {
67
$this->attributes[$key] = $value;
68
return $this;
69
}
70
71
public function getCapability($key, $default = null) {
72
return idx($this->capbilities, $key, $default);
73
}
74
75
public function getInterface(DrydockLease $lease, $type) {
76
return $this->getBlueprint()->getInterface($this, $lease, $type);
77
}
78
79
public function getBlueprint() {
80
return $this->assertAttached($this->blueprint);
81
}
82
83
public function attachBlueprint(DrydockBlueprint $blueprint) {
84
$this->blueprint = $blueprint;
85
return $this;
86
}
87
88
public function getUnconsumedCommands() {
89
return $this->assertAttached($this->unconsumedCommands);
90
}
91
92
public function attachUnconsumedCommands(array $commands) {
93
$this->unconsumedCommands = $commands;
94
return $this;
95
}
96
97
public function isReleasing() {
98
foreach ($this->getUnconsumedCommands() as $command) {
99
if ($command->getCommand() == DrydockCommand::COMMAND_RELEASE) {
100
return true;
101
}
102
}
103
104
return false;
105
}
106
107
public function setActivateWhenAllocated($activate) {
108
$this->activateWhenAllocated = $activate;
109
return $this;
110
}
111
112
public function needSlotLock($key) {
113
$this->slotLocks[] = $key;
114
return $this;
115
}
116
117
public function allocateResource() {
118
// We expect resources to have a pregenerated PHID, as they should have
119
// been created by a call to DrydockBlueprint->newResourceTemplate().
120
if (!$this->getPHID()) {
121
throw new Exception(
122
pht(
123
'Trying to allocate a resource with no generated PHID. Use "%s" to '.
124
'create new resource templates.',
125
'newResourceTemplate()'));
126
}
127
128
$expect_status = DrydockResourceStatus::STATUS_PENDING;
129
$actual_status = $this->getStatus();
130
if ($actual_status != $expect_status) {
131
throw new Exception(
132
pht(
133
'Trying to allocate a resource from the wrong status. Status must '.
134
'be "%s", actually "%s".',
135
$expect_status,
136
$actual_status));
137
}
138
139
if ($this->activateWhenAllocated) {
140
$new_status = DrydockResourceStatus::STATUS_ACTIVE;
141
} else {
142
$new_status = DrydockResourceStatus::STATUS_PENDING;
143
}
144
145
$this->openTransaction();
146
147
try {
148
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
149
$this->slotLocks = array();
150
} catch (DrydockSlotLockException $ex) {
151
$this->killTransaction();
152
153
if ($this->getID()) {
154
$log_target = $this;
155
} else {
156
// If we don't have an ID, we have to log this on the blueprint, as the
157
// resource is not going to be saved so the PHID will vanish.
158
$log_target = $this->getBlueprint();
159
}
160
$log_target->logEvent(
161
DrydockSlotLockFailureLogType::LOGCONST,
162
array(
163
'locks' => $ex->getLockMap(),
164
));
165
166
throw $ex;
167
}
168
169
$this
170
->setStatus($new_status)
171
->save();
172
173
$this->saveTransaction();
174
175
$this->isAllocated = true;
176
177
if ($new_status == DrydockResourceStatus::STATUS_ACTIVE) {
178
$this->didActivate();
179
}
180
181
return $this;
182
}
183
184
public function isAllocatedResource() {
185
return $this->isAllocated;
186
}
187
188
public function activateResource() {
189
if (!$this->getID()) {
190
throw new Exception(
191
pht(
192
'Trying to activate a resource which has not yet been persisted.'));
193
}
194
195
$expect_status = DrydockResourceStatus::STATUS_PENDING;
196
$actual_status = $this->getStatus();
197
if ($actual_status != $expect_status) {
198
throw new Exception(
199
pht(
200
'Trying to activate a resource from the wrong status. Status must '.
201
'be "%s", actually "%s".',
202
$expect_status,
203
$actual_status));
204
}
205
206
$this->openTransaction();
207
208
try {
209
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
210
$this->slotLocks = array();
211
} catch (DrydockSlotLockException $ex) {
212
$this->killTransaction();
213
214
$this->logEvent(
215
DrydockSlotLockFailureLogType::LOGCONST,
216
array(
217
'locks' => $ex->getLockMap(),
218
));
219
220
throw $ex;
221
}
222
223
$this
224
->setStatus(DrydockResourceStatus::STATUS_ACTIVE)
225
->save();
226
227
$this->saveTransaction();
228
229
$this->isActivated = true;
230
231
$this->didActivate();
232
233
return $this;
234
}
235
236
public function isActivatedResource() {
237
return $this->isActivated;
238
}
239
240
public function scheduleUpdate($epoch = null) {
241
PhabricatorWorker::scheduleTask(
242
'DrydockResourceUpdateWorker',
243
array(
244
'resourcePHID' => $this->getPHID(),
245
'isExpireTask' => ($epoch !== null),
246
),
247
array(
248
'objectPHID' => $this->getPHID(),
249
'delayUntil' => ($epoch ? (int)$epoch : null),
250
));
251
}
252
253
private function didActivate() {
254
$viewer = PhabricatorUser::getOmnipotentUser();
255
256
$need_update = false;
257
258
$commands = id(new DrydockCommandQuery())
259
->setViewer($viewer)
260
->withTargetPHIDs(array($this->getPHID()))
261
->withConsumed(false)
262
->execute();
263
if ($commands) {
264
$need_update = true;
265
}
266
267
if ($need_update) {
268
$this->scheduleUpdate();
269
}
270
271
$expires = $this->getUntil();
272
if ($expires) {
273
$this->scheduleUpdate($expires);
274
}
275
}
276
277
public function logEvent($type, array $data = array()) {
278
$log = id(new DrydockLog())
279
->setEpoch(PhabricatorTime::getNow())
280
->setType($type)
281
->setData($data);
282
283
$log->setResourcePHID($this->getPHID());
284
$log->setBlueprintPHID($this->getBlueprintPHID());
285
286
return $log->save();
287
}
288
289
public function getDisplayName() {
290
return pht('Drydock Resource %d', $this->getID());
291
}
292
293
294
/* -( Status )------------------------------------------------------------- */
295
296
297
public function getStatusObject() {
298
return DrydockResourceStatus::newStatusObject($this->getStatus());
299
}
300
301
public function getStatusIcon() {
302
return $this->getStatusObject()->getIcon();
303
}
304
305
public function getStatusColor() {
306
return $this->getStatusObject()->getColor();
307
}
308
309
public function getStatusDisplayName() {
310
return $this->getStatusObject()->getDisplayName();
311
}
312
313
public function canRelease() {
314
return $this->getStatusObject()->canRelease();
315
}
316
317
public function canReceiveCommands() {
318
return $this->getStatusObject()->canReceiveCommands();
319
}
320
321
public function isActive() {
322
return $this->getStatusObject()->isActive();
323
}
324
325
326
/* -( PhabricatorPolicyInterface )----------------------------------------- */
327
328
329
public function getCapabilities() {
330
return array(
331
PhabricatorPolicyCapability::CAN_VIEW,
332
PhabricatorPolicyCapability::CAN_EDIT,
333
);
334
}
335
336
public function getPolicy($capability) {
337
return $this->getBlueprint()->getPolicy($capability);
338
}
339
340
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
341
return $this->getBlueprint()->hasAutomaticCapability(
342
$capability,
343
$viewer);
344
}
345
346
public function describeAutomaticCapability($capability) {
347
return pht('Resources inherit the policies of their blueprints.');
348
}
349
350
351
/* -( PhabricatorConduitResultInterface )---------------------------------- */
352
353
354
public function getFieldSpecificationsForConduit() {
355
return array(
356
id(new PhabricatorConduitSearchFieldSpecification())
357
->setKey('blueprintPHID')
358
->setType('phid')
359
->setDescription(pht('The blueprint which generated this resource.')),
360
id(new PhabricatorConduitSearchFieldSpecification())
361
->setKey('status')
362
->setType('map<string, wild>')
363
->setDescription(pht('Information about resource status.')),
364
);
365
}
366
367
public function getFieldValuesForConduit() {
368
$status = $this->getStatus();
369
370
return array(
371
'blueprintPHID' => $this->getBlueprintPHID(),
372
'status' => array(
373
'value' => $status,
374
'name' => DrydockResourceStatus::getNameForStatus($status),
375
),
376
);
377
}
378
379
public function getConduitSearchAttachments() {
380
return array();
381
}
382
383
}
384
385