GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#187)
by Chris
07:33
created

Server::unrescue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php declare(strict_types=1);
2
3
namespace OpenStack\Compute\v2\Models;
4
5
use OpenStack\Common\Resource\Alias;
6
use OpenStack\Common\Resource\HasWaiterTrait;
7
use OpenStack\Common\Resource\Creatable;
8
use OpenStack\Common\Resource\Deletable;
9
use OpenStack\Common\Resource\Listable;
10
use OpenStack\Common\Resource\Retrievable;
11
use OpenStack\Common\Resource\Updateable;
12
use OpenStack\Common\Resource\OperatorResource;
13
use OpenStack\Common\Transport\Utils;
14
use OpenStack\BlockStorage\v2\Models\VolumeAttachment;
15
use OpenStack\Networking\v2\Models\InterfaceAttachment;
16
use OpenStack\Compute\v2\Enum;
17
use OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup;
18
use Psr\Http\Message\ResponseInterface;
19
20
/**
21
 * @property \OpenStack\Compute\v2\Api $api
22
 */
23
class Server extends OperatorResource implements
24
    Creatable,
25
    Updateable,
26
    Deletable,
27
    Retrievable,
28
    Listable
29
{
30
    use HasWaiterTrait;
31
32
    /** @var string */
33
    public $id;
34
35
    /** @var string */
36
    public $ipv4;
37
38
    /** @var string */
39
    public $ipv6;
40
41
    /** @var array */
42
    public $addresses;
43
44
    /** @var \DateTimeImmutable */
45
    public $created;
46
47
    /** @var \DateTimeImmutable */
48
    public $updated;
49
50
    /** @var Flavor */
51
    public $flavor;
52
53
    /** @var string */
54
    public $hostId;
55
56
    /** @var string */
57
    public $hypervisorHostname;
58
59
    /** @var Image */
60
    public $image;
61
62
    /** @var array */
63
    public $links;
64
65
    /** @var array */
66
    public $metadata;
67
68
    /** @var string */
69
    public $name;
70
71
    /** @var string */
72
    public $progress;
73
74
    /** @var string */
75
    public $status;
76
77
    /** @var string */
78
    public $tenantId;
79
80
    /** @var string */
81
    public $userId;
82
83
    /** @var string */
84
    public $adminPass;
85
86
    /** @var string */
87
    public $taskState;
88
89
    /** @var string */
90
    public $powerState;
91
92
    /** @var string */
93
    public $vmState;
94
95
    /** @var Fault */
96
    public $fault;
97
98
    protected $resourceKey = 'server';
99
    protected $resourcesKey = 'servers';
100
    protected $markerKey = 'id';
101 2
102
    protected $aliases = [
103 2
        'block_device_mapping_v2'             => 'blockDeviceMapping',
104 2
        'accessIPv4'                          => 'ipv4',
105
        'accessIPv6'                          => 'ipv6',
106
        'tenant_id'                           => 'tenantId',
107
        'user_id'                             => 'userId',
108
        'security_groups'                     => 'securityGroups',
109
        'OS-EXT-STS:task_state'               => 'taskState',
110 1
        'OS-EXT-STS:power_state'              => 'powerState',
111
        'OS-EXT-STS:vm_state'                 => 'vmState',
112 1
        'OS-EXT-SRV-ATTR:hypervisor_hostname' => 'hypervisorHostname',
113
    ];
114 1
115
    /**
116
     * @inheritdoc
117
     */
118 View Code Duplication
    protected function getAliases(): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
119
    {
120 1
        return parent::getAliases() + [
121
            'image'   => new Alias('image', Image::class),
122 1
            'flavor'  => new Alias('flavor', Flavor::class),
123 1
            'created' => new Alias('created', \DateTimeImmutable::class),
124
            'updated' => new Alias('updated', \DateTimeImmutable::class)
125
        ];
126
    }
127
128 1
    /**
129
     * {@inheritDoc}
130 1
     *
131
     * @param array $userOptions {@see \OpenStack\Compute\v2\Api::postServer}
132 1
     */
133
    public function create(array $userOptions): Creatable
134
    {
135
        if (!isset($userOptions['imageId']) && !isset($userOptions['blockDeviceMapping'][0]['uuid'])) {
136
            throw new \RuntimeException('imageId or blockDeviceMapping.uuid must be set.');
137
        }
138
139
        $response = $this->execute($this->api->postServer(), $userOptions);
140 1
        return $this->populateFromResponse($response);
141
    }
142 1
143 1
    /**
144
     * {@inheritDoc}
145 1
     */
146 1
    public function update()
147
    {
148
        $response = $this->execute($this->api->putServer(), $this->getAttrs(['id', 'name', 'ipv4', 'ipv6']));
149
        $this->populateFromResponse($response);
150
    }
151
152
    /**
153 2
     * {@inheritDoc}
154
     */
155 2
    public function delete()
156 1
    {
157
        $this->execute($this->api->deleteServer(), $this->getAttrs(['id']));
158
    }
159 1
160 1
    /**
161 1
     * {@inheritDoc}
162 1
     */
163 1
    public function retrieve()
164
    {
165
        $response = $this->execute($this->api->getServer(), $this->getAttrs(['id']));
166
        $this->populateFromResponse($response);
167
    }
168
169
    /**
170 1
     * Changes the root password for a server.
171
     *
172 1
     * @param string $newPassword The new root password
173 1
     */
174
    public function changePassword(string $newPassword)
175 1
    {
176 1
        $this->execute($this->api->changeServerPassword(), [
177
            'id'       => $this->id,
178
            'password' => $newPassword,
179
        ]);
180
    }
181
182
    /**
183
     * Reboots the server.
184 1
     *
185
     * @param string $type The type of reboot that will be performed. Either SOFT or HARD is supported.
186 1
     */
187 1
    public function reboot(string $type = Enum::REBOOT_SOFT)
188 1
    {
189 1
        if (!in_array($type, ['SOFT', 'HARD'])) {
190
            throw new \RuntimeException('Reboot type must either be SOFT or HARD');
191 1
        }
192 1
193
        $this->execute($this->api->rebootServer(), [
194
            'id'   => $this->id,
195
            'type' => $type,
196
        ]);
197 1
    }
198
199 1
    /**
200 1
     * Starts server
201
     */
202
    public function start()
203
    {
204
        $this->execute($this->api->startServer(), [
205 1
            'id' => $this->id,
206
            'os-start' => null
207 1
        ]);
208 1
    }
209
210
    /**
211
     * Stops server
212
     */
213
    public function stop()
214
    {
215 1
        $this->execute($this->api->stopServer(), [
216
            'id' => $this->id,
217 1
            'os-stop' => null
218 1
        ]);
219 1
    }
220
221
    /**
222
     * Shelves server
223
     */
224
    public function shelve()
225
    {
226
        $this->execute($this->api->shelveServer(), [
227
            'id' => $this->id,
228 2
            'shelve' => null
229
        ]);
230 2
    }
231
232 2
    /*
233 2
     * Suspend server
234 2
     */
235
    public function suspend()
236
    {
237
        $this->execute($this->api->suspendServer(), [
238
            'id' => $this->id,
239
            'suspend' => null
240
        ]);
241
    }
242 1
243
    /**
244 1
     * Shelf-offloads server
245 1
     */
246
    public function shelveOffload()
247
    {
248
        $this->execute($this->api->shelveOffloadServer(), [
249
            'id' => $this->id,
250
            'shelveOffload' => null
251
        ]);
252
    }
253
254
    /**
255
     * Unshelves server
256 1
     */
257
    public function unshelve()
258 1
    {
259 1
        $this->execute($this->api->unshelveServer(), [
260
            'id' => $this->id,
261
            'unshelve' => null
262
        ]);
263
    }
264
265
    /*
266
     * Resume server
267
     */
268
    public function resume()
269
    {
270
        $this->execute($this->api->resumeServer(), [
271 1
            'id' => $this->id,
272
            'resume' => null
273 1
        ]);
274 1
    }
275
276
    /**
277
     * Locks server
278
     */
279
    public function lock()
280
    {
281
        $this->execute($this->api->lockServer(), [
282
            'id' => $this->id,
283
            'lock' => null
284 1
        ]);
285
    }
286 1
287 1
    /**
288
     * Unlocks server
289
     */
290
    public function unlock()
291
    {
292
        $this->execute($this->api->unlockServer(), [
293
            'id' => $this->id,
294
            'unlock' => null
295 1
        ]);
296
    }
297 1
298 1
    /**
299
     * Rebuilds the server.
300
     *
301
     * @param array $options {@see \OpenStack\Compute\v2\Api::rebuildServer}
302
     */
303
    public function rebuild(array $options)
304
    {
305
        $options['id'] = $this->id;
306
        $response = $this->execute($this->api->rebuildServer(), $options);
307
308
        $this->populateFromResponse($response);
309
    }
310
311
    /**
312
     * Rescues the server.
313
     *
314
     * @param array $options {@see \OpenStack\Compute\v2\Api::rescueServer}
315
     * @return string
316
     */
317
    public function rescue(array $options): string
318
    {
319
        $options['id'] = $this->id;
320
        $response = $this->execute($this->api->rescueServer(), $options);
321
322
        return Utils::jsonDecode($response)['adminPass'];
323
    }
324
325
    /**
326
     * Unrescues the server.
327
     */
328
    public function unrescue()
329
    {
330
        $this->execute($this->api->unrescueServer(), ['unrescue' => null, 'id' => $this->id]);
331
    }
332
333
    /**
334
     * Resizes the server to a new flavor. Once this operation is complete and server has transitioned
335
     * to an active state, you will either need to call {@see confirmResize()} or {@see revertResize()}.
336
     *
337
     * @param string $flavorId The UUID of the new flavor your server will be based on.
338
     */
339
    public function resize(string $flavorId)
340
    {
341
        $response = $this->execute($this->api->resizeServer(), [
342
            'id'       => $this->id,
343
            'flavorId' => $flavorId,
344
        ]);
345
346
        $this->populateFromResponse($response);
347
    }
348
349
    /**
350
     * Confirms a previous resize operation.
351
     */
352
    public function confirmResize()
353
    {
354
        $this->execute($this->api->confirmServerResize(), ['confirmResize' => null, 'id' => $this->id]);
355
    }
356
357
    /**
358
     * Reverts a previous resize operation.
359
     */
360
    public function revertResize()
361
    {
362
        $this->execute($this->api->revertServerResize(), ['revertResize' => null, 'id' => $this->id]);
363
    }
364
365
    /**
366
     * Gets a VNC console for a server.
367
     *
368
     * @param  string $type The type of VNC console: novnc|xvpvnc.
369
     *                      Defaults to novnc.
370
     *
371
     * @return array
372
     */
373
    public function getVncConsole($type = Enum::CONSOLE_NOVNC): array
374
    {
375
        $response = $this->execute($this->api->getVncConsole(), ['id' => $this->id, 'type' => $type]);
376
        return Utils::jsonDecode($response)['console'];
377
    }
378
379
    /**
380
     * Gets a RDP console for a server.
381
     *
382
     * @param  string $type The type of VNC console: rdp-html5 (default).
383
     *
384
     * @return array
385
     */
386
    public function getRDPConsole($type = Enum::CONSOLE_RDP_HTML5): array
387
    {
388
        $response = $this->execute($this->api->getRDPConsole(), ['id' => $this->id, 'type' => $type]);
389
        return Utils::jsonDecode($response)['console'];
390
    }
391
392
    /**
393
     * Gets a Spice console for a server.
394
     *
395
     * @param  string $type The type of VNC console: spice-html5.
396
     *
397
     * @return array
398
     */
399
    public function getSpiceConsole($type = Enum::CONSOLE_SPICE_HTML5): array
400
    {
401
        $response = $this->execute($this->api->getSpiceConsole(), ['id' => $this->id, 'type' => $type]);
402
        return Utils::jsonDecode($response)['console'];
403
    }
404
405
    /**
406
     * Gets a serial console for a server.
407
     *
408
     * @param  string $type The type of VNC console: serial.
409
     *
410
     * @return array
411
     */
412
    public function getSerialConsole($type = Enum::CONSOLE_SERIAL): array
413
    {
414
        $response = $this->execute($this->api->getSerialConsole(), ['id' => $this->id, 'type' => $type]);
415
        return Utils::jsonDecode($response)['console'];
416
    }
417
418
    /**
419
     * Get the console log.
420
     *
421
     * @param int $length Number of lines of console log to grab.
422
     *
423
     * @return string - the console log output
424
     */
425
    public function getConsoleLog(int $length = 50): string
426
    {
427
        $response = $this->execute($this->api->getConsoleLog(), ['id' => $this->id, 'length' => $length]);
428
        return Utils::jsonDecode($response)['output'];
429
    }
430
431
    /**
432
     * Creates an image for the current server.
433
     *
434
     * @param array $options {@see \OpenStack\Compute\v2\Api::createServerImage}
435
     */
436
    public function createImage(array $options)
437
    {
438
        $options['id'] = $this->id;
439
        $this->execute($this->api->createServerImage(), $options);
440
    }
441
442
    /**
443
     * Iterates over all the IP addresses for this server.
444
     *
445
     * @param array $options {@see \OpenStack\Compute\v2\Api::getAddressesByNetwork}
446
     *
447
     * @return array An array containing to two keys: "public" and "private"
448
     */
449
    public function listAddresses(array $options = []): array
450
    {
451
        $options['id'] = $this->id;
452
453
        $data = (isset($options['networkLabel'])) ? $this->api->getAddressesByNetwork() : $this->api->getAddresses();
454
        $response = $this->execute($data, $options);
455
        return Utils::jsonDecode($response)['addresses'];
456
    }
457
458
    /**
459
     * Returns Generator for InterfaceAttachment
460
     *
461
     * @return \Generator
462
     */
463
    public function listInterfaceAttachments(array $options = []): \Generator
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
464
    {
465
        return $this->model(InterfaceAttachment::class)->enumerate($this->api->getInterfaceAttachments(), ['id' => $this->id]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OpenStack\Common\Resource\ResourceInterface as the method enumerate() does only exist in the following implementations of said interface: OpenStack\BlockStorage\v2\Models\QuotaSet, OpenStack\BlockStorage\v2\Models\Snapshot, OpenStack\BlockStorage\v2\Models\Volume, OpenStack\BlockStorage\v2\Models\VolumeAttachment, OpenStack\BlockStorage\v2\Models\VolumeType, OpenStack\Common\Resource\OperatorResource, OpenStack\Compute\v2\Models\Aggregate, OpenStack\Compute\v2\Models\AvailabilityZone, OpenStack\Compute\v2\Models\Flavor, OpenStack\Compute\v2\Models\Host, OpenStack\Compute\v2\Models\Hypervisor, OpenStack\Compute\v2\Models\HypervisorStatistic, OpenStack\Compute\v2\Models\Image, OpenStack\Compute\v2\Models\InstanceAction, OpenStack\Compute\v2\Models\Keypair, OpenStack\Compute\v2\Models\QuotaSet, OpenStack\Compute\v2\Models\Server, OpenStack\Identity\v2\Models\Catalog, OpenStack\Identity\v2\Models\Endpoint, OpenStack\Identity\v2\Models\Entry, OpenStack\Identity\v2\Models\Tenant, OpenStack\Identity\v2\Models\Token, OpenStack\Identity\v3\Models\Assignment, OpenStack\Identity\v3\Models\Catalog, OpenStack\Identity\v3\Models\Credential, OpenStack\Identity\v3\Models\Domain, OpenStack\Identity\v3\Models\Endpoint, OpenStack\Identity\v3\Models\Group, OpenStack\Identity\v3\Models\Policy, OpenStack\Identity\v3\Models\Project, OpenStack\Identity\v3\Models\Role, OpenStack\Identity\v3\Models\Service, OpenStack\Identity\v3\Models\Token, OpenStack\Identity\v3\Models\User, OpenStack\Images\v2\Models\Image, OpenStack\Images\v2\Models\Member, OpenStack\Metric\v1\Gnocchi\Models\Metric, OpenStack\Metric\v1\Gnocchi\Models\Resource, OpenStack\Metric\v1\Gnocchi\Models\ResourceType, OpenStack\Networking\v2\...ayer3\Models\FloatingIp, OpenStack\Networking\v2\...ns\Layer3\Models\Router, OpenStack\Networking\v2\...ps\Models\SecurityGroup, OpenStack\Networking\v2\...odels\SecurityGroupRule, OpenStack\Networking\v2\Models\InterfaceAttachment, OpenStack\Networking\v2\Models\LoadBalancer, OpenStack\Networking\v2\...adBalancerHealthMonitor, OpenStack\Networking\v2\...ls\LoadBalancerListener, OpenStack\Networking\v2\Models\LoadBalancerMember, OpenStack\Networking\v2\Models\LoadBalancerPool, OpenStack\Networking\v2\Models\LoadBalancerStat, OpenStack\Networking\v2\Models\LoadBalancerStatus, OpenStack\Networking\v2\Models\Network, OpenStack\Networking\v2\...s\NetworkIpAvailability, OpenStack\Networking\v2\Models\Port, OpenStack\Networking\v2\Models\Quota, OpenStack\Networking\v2\Models\Subnet, OpenStack\ObjectStore\v1\Models\Account, OpenStack\ObjectStore\v1\Models\Container, OpenStack\ObjectStore\v1\Models\Object.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
466
    }
467
468
    /**
469
     * Gets an interface attachment.
470
     *
471
     * @param string $portId The unique ID of the port.
472
     * @return InterfaceAttachment
473
     */
474 View Code Duplication
    public function getInterfaceAttachment(string $portId): InterfaceAttachment
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
475
    {
476
        $response = $this->execute($this->api->getInterfaceAttachment(), [
477
            'id'     => $this->id,
478
            'portId' => $portId
479
        ]);
480
481
        return $this->model(InterfaceAttachment::class)->populateFromResponse($response);
482
    }
483
484
    /**
485
     * Creates an interface attachment.
486
     *
487
     * @param array $userOptions {@see \OpenStack\Compute\v2\Api::postInterfaceAttachment}
488
     * @return InterfaceAttachment
489
     */
490
    public function createInterfaceAttachment(array $userOptions): InterfaceAttachment
491
    {
492
        if (!isset($userOptions['networkId']) && !isset($userOptions['portId'])) {
493
            throw new \RuntimeException('networkId or portId must be set.');
494
        }
495
496
        $response = $this->execute($this->api->postInterfaceAttachment(), array_merge($userOptions, ['id' => $this->id]));
497
        return $this->model(InterfaceAttachment::class)->populateFromResponse($response);
498
    }
499
500
    /**
501
     * Detaches an interface attachment.
502
     *
503
     * @param string $portId
504
     */
505
    public function detachInterface(string $portId)
506
    {
507
        $this->execute($this->api->deleteInterfaceAttachment(), [
508
            'id' => $this->id,
509
            'portId' => $portId,
510
        ]);
511
    }
512
513
    /**
514
     * Retrieves metadata from the API.
515
     *
516
     * @return array
517
     */
518
    public function getMetadata(): array
519
    {
520
        $response = $this->execute($this->api->getServerMetadata(), ['id' => $this->id]);
521
        return $this->parseMetadata($response);
522
    }
523
524
    /**
525
     * Resets all the metadata for this server with the values provided. All existing metadata keys
526
     * will either be replaced or removed.
527
     *
528
     * @param array $metadata {@see \OpenStack\Compute\v2\Api::putServerMetadata}
529
     */
530
    public function resetMetadata(array $metadata)
531
    {
532
        $response = $this->execute($this->api->putServerMetadata(), ['id' => $this->id, 'metadata' => $metadata]);
533
        $this->metadata = $this->parseMetadata($response);
534
    }
535
536
    /**
537
     * Merges the existing metadata for the server with the values provided. Any existing keys
538
     * referenced in the user options will be replaced with the user's new values. All other
539
     * existing keys will remain unaffected.
540
     *
541
     * @param array $metadata {@see \OpenStack\Compute\v2\Api::postServerMetadata}
542
     *
543
     * @return array
544
     */
545
    public function mergeMetadata(array $metadata)
546
    {
547
        $response = $this->execute($this->api->postServerMetadata(), ['id' => $this->id, 'metadata' => $metadata]);
548
        $this->metadata = $this->parseMetadata($response);
549
    }
550
551
    /**
552
     * Retrieve the value for a specific metadata key.
553
     *
554
     * @param string $key {@see \OpenStack\Compute\v2\Api::getServerMetadataKey}
555
     *
556
     * @return mixed
557
     */
558 View Code Duplication
    public function getMetadataItem(string $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
559
    {
560
        $response = $this->execute($this->api->getServerMetadataKey(), ['id' => $this->id, 'key' => $key]);
561
        $value = $this->parseMetadata($response)[$key];
562
        $this->metadata[$key] = $value;
563
        return $value;
564
    }
565
566
    /**
567
     * Remove a specific metadata key.
568
     *
569
     * @param string $key {@see \OpenStack\Compute\v2\Api::deleteServerMetadataKey}
570
     */
571 View Code Duplication
    public function deleteMetadataItem(string $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
572
    {
573
        if (isset($this->metadata[$key])) {
574
            unset($this->metadata[$key]);
575
        }
576
577
        $this->execute($this->api->deleteServerMetadataKey(), ['id' => $this->id, 'key' => $key]);
578
    }
579
580
581
    /**
582
     * Add security group to a server (addSecurityGroup action)
583
     *
584
     * @param array $options {@see \OpenStack\Compute\v2\Api::postSecurityGroup}
585
     *
586
     * @return SecurityGroup
587
     */
588 View Code Duplication
    public function addSecurityGroup(array $options) : SecurityGroup
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
589
    {
590
        $options['id'] = $this->id;
591
592
        $response = $this->execute($this->api->postSecurityGroup(), $options);
593
594
        return $this->model(SecurityGroup::class)->populateFromResponse($response);
595
    }
596
597
    /**
598
     * Add security group to a server (addSecurityGroup action)
599
     *
600
     * @param array $options {@see \OpenStack\Compute\v2\Api::deleteSecurityGroup}
601
     */
602
    public function removeSecurityGroup(array $options)
603
    {
604
        $options['id'] = $this->id;
605
        $this->execute($this->api->deleteSecurityGroup(), $options);
606
    }
607
608
    public function parseMetadata(ResponseInterface $response): array
609
    {
610
        return Utils::jsonDecode($response)['metadata'];
611
    }
612
613
    /**
614
     * Returns Generator for SecurityGroups
615
     *
616
     * @return \Generator
617
     */
618
    public function listSecurityGroups(): \Generator
619
    {
620
        return $this->model(SecurityGroup::class)->enumerate($this->api->getSecurityGroups(), ['id' => $this->id]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OpenStack\Common\Resource\ResourceInterface as the method enumerate() does only exist in the following implementations of said interface: OpenStack\BlockStorage\v2\Models\QuotaSet, OpenStack\BlockStorage\v2\Models\Snapshot, OpenStack\BlockStorage\v2\Models\Volume, OpenStack\BlockStorage\v2\Models\VolumeAttachment, OpenStack\BlockStorage\v2\Models\VolumeType, OpenStack\Common\Resource\OperatorResource, OpenStack\Compute\v2\Models\Aggregate, OpenStack\Compute\v2\Models\AvailabilityZone, OpenStack\Compute\v2\Models\Flavor, OpenStack\Compute\v2\Models\Host, OpenStack\Compute\v2\Models\Hypervisor, OpenStack\Compute\v2\Models\HypervisorStatistic, OpenStack\Compute\v2\Models\Image, OpenStack\Compute\v2\Models\InstanceAction, OpenStack\Compute\v2\Models\Keypair, OpenStack\Compute\v2\Models\QuotaSet, OpenStack\Compute\v2\Models\Server, OpenStack\Identity\v2\Models\Catalog, OpenStack\Identity\v2\Models\Endpoint, OpenStack\Identity\v2\Models\Entry, OpenStack\Identity\v2\Models\Tenant, OpenStack\Identity\v2\Models\Token, OpenStack\Identity\v3\Models\Assignment, OpenStack\Identity\v3\Models\Catalog, OpenStack\Identity\v3\Models\Credential, OpenStack\Identity\v3\Models\Domain, OpenStack\Identity\v3\Models\Endpoint, OpenStack\Identity\v3\Models\Group, OpenStack\Identity\v3\Models\Policy, OpenStack\Identity\v3\Models\Project, OpenStack\Identity\v3\Models\Role, OpenStack\Identity\v3\Models\Service, OpenStack\Identity\v3\Models\Token, OpenStack\Identity\v3\Models\User, OpenStack\Images\v2\Models\Image, OpenStack\Images\v2\Models\Member, OpenStack\Metric\v1\Gnocchi\Models\Metric, OpenStack\Metric\v1\Gnocchi\Models\Resource, OpenStack\Metric\v1\Gnocchi\Models\ResourceType, OpenStack\Networking\v2\...ayer3\Models\FloatingIp, OpenStack\Networking\v2\...ns\Layer3\Models\Router, OpenStack\Networking\v2\...ps\Models\SecurityGroup, OpenStack\Networking\v2\...odels\SecurityGroupRule, OpenStack\Networking\v2\Models\InterfaceAttachment, OpenStack\Networking\v2\Models\LoadBalancer, OpenStack\Networking\v2\...adBalancerHealthMonitor, OpenStack\Networking\v2\...ls\LoadBalancerListener, OpenStack\Networking\v2\Models\LoadBalancerMember, OpenStack\Networking\v2\Models\LoadBalancerPool, OpenStack\Networking\v2\Models\LoadBalancerStat, OpenStack\Networking\v2\Models\LoadBalancerStatus, OpenStack\Networking\v2\Models\Network, OpenStack\Networking\v2\...s\NetworkIpAvailability, OpenStack\Networking\v2\Models\Port, OpenStack\Networking\v2\Models\Quota, OpenStack\Networking\v2\Models\Subnet, OpenStack\ObjectStore\v1\Models\Account, OpenStack\ObjectStore\v1\Models\Container, OpenStack\ObjectStore\v1\Models\Object.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
621
    }
622
623
624
    /**
625
     * Returns Generator for VolumeAttachment
626
     *
627
     * @return \Generator
628
     */
629
    public function listVolumeAttachments(): \Generator
630
    {
631
        return $this->model(VolumeAttachment::class)->enumerate($this->api->getVolumeAttachments(), ['id' => $this->id]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OpenStack\Common\Resource\ResourceInterface as the method enumerate() does only exist in the following implementations of said interface: OpenStack\BlockStorage\v2\Models\QuotaSet, OpenStack\BlockStorage\v2\Models\Snapshot, OpenStack\BlockStorage\v2\Models\Volume, OpenStack\BlockStorage\v2\Models\VolumeAttachment, OpenStack\BlockStorage\v2\Models\VolumeType, OpenStack\Common\Resource\OperatorResource, OpenStack\Compute\v2\Models\Aggregate, OpenStack\Compute\v2\Models\AvailabilityZone, OpenStack\Compute\v2\Models\Flavor, OpenStack\Compute\v2\Models\Host, OpenStack\Compute\v2\Models\Hypervisor, OpenStack\Compute\v2\Models\HypervisorStatistic, OpenStack\Compute\v2\Models\Image, OpenStack\Compute\v2\Models\InstanceAction, OpenStack\Compute\v2\Models\Keypair, OpenStack\Compute\v2\Models\QuotaSet, OpenStack\Compute\v2\Models\Server, OpenStack\Identity\v2\Models\Catalog, OpenStack\Identity\v2\Models\Endpoint, OpenStack\Identity\v2\Models\Entry, OpenStack\Identity\v2\Models\Tenant, OpenStack\Identity\v2\Models\Token, OpenStack\Identity\v3\Models\Assignment, OpenStack\Identity\v3\Models\Catalog, OpenStack\Identity\v3\Models\Credential, OpenStack\Identity\v3\Models\Domain, OpenStack\Identity\v3\Models\Endpoint, OpenStack\Identity\v3\Models\Group, OpenStack\Identity\v3\Models\Policy, OpenStack\Identity\v3\Models\Project, OpenStack\Identity\v3\Models\Role, OpenStack\Identity\v3\Models\Service, OpenStack\Identity\v3\Models\Token, OpenStack\Identity\v3\Models\User, OpenStack\Images\v2\Models\Image, OpenStack\Images\v2\Models\Member, OpenStack\Metric\v1\Gnocchi\Models\Metric, OpenStack\Metric\v1\Gnocchi\Models\Resource, OpenStack\Metric\v1\Gnocchi\Models\ResourceType, OpenStack\Networking\v2\...ayer3\Models\FloatingIp, OpenStack\Networking\v2\...ns\Layer3\Models\Router, OpenStack\Networking\v2\...ps\Models\SecurityGroup, OpenStack\Networking\v2\...odels\SecurityGroupRule, OpenStack\Networking\v2\Models\InterfaceAttachment, OpenStack\Networking\v2\Models\LoadBalancer, OpenStack\Networking\v2\...adBalancerHealthMonitor, OpenStack\Networking\v2\...ls\LoadBalancerListener, OpenStack\Networking\v2\Models\LoadBalancerMember, OpenStack\Networking\v2\Models\LoadBalancerPool, OpenStack\Networking\v2\Models\LoadBalancerStat, OpenStack\Networking\v2\Models\LoadBalancerStatus, OpenStack\Networking\v2\Models\Network, OpenStack\Networking\v2\...s\NetworkIpAvailability, OpenStack\Networking\v2\Models\Port, OpenStack\Networking\v2\Models\Quota, OpenStack\Networking\v2\Models\Subnet, OpenStack\ObjectStore\v1\Models\Account, OpenStack\ObjectStore\v1\Models\Container, OpenStack\ObjectStore\v1\Models\Object.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
632
    }
633
634
    /**
635
     * Attach a volume and returns volume that was attached
636
     *
637
     * @param $volumeId
638
     *
639
     * @return VolumeAttachment
640
     */
641
    public function attachVolume(string $volumeId): VolumeAttachment
642
    {
643
        $response =  $this->execute($this->api->postVolumeAttachments(), ['id' => $this->id, 'volumeId' => $volumeId]);
644
645
        return $this->model(VolumeAttachment::class)->populateFromResponse($response);
646
    }
647
648
    /**
649
     * Detach a volume
650
     *
651
     * @param $attachmentId
652
     *
653
     * @return void
654
     */
655
    public function detachVolume(string $attachmentId)
656
    {
657
        $this->execute($this->api->deleteVolumeAttachments(), ['id' => $this->id, 'attachmentId' => $attachmentId]);
658
    }
659
660
    /**
661
     * Get a Generator for the instance actions
662
     *
663
     * @return \Generator
664
     */
665
    public function listInstanceActions(): \Generator
666
    {
667
        return $this->model(InstanceAction::class)->enumerate($this->api->getInstanceActions(), ['id' => $this->id]);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OpenStack\Common\Resource\ResourceInterface as the method enumerate() does only exist in the following implementations of said interface: OpenStack\BlockStorage\v2\Models\QuotaSet, OpenStack\BlockStorage\v2\Models\Snapshot, OpenStack\BlockStorage\v2\Models\Volume, OpenStack\BlockStorage\v2\Models\VolumeAttachment, OpenStack\BlockStorage\v2\Models\VolumeType, OpenStack\Common\Resource\OperatorResource, OpenStack\Compute\v2\Models\Aggregate, OpenStack\Compute\v2\Models\AvailabilityZone, OpenStack\Compute\v2\Models\Flavor, OpenStack\Compute\v2\Models\Host, OpenStack\Compute\v2\Models\Hypervisor, OpenStack\Compute\v2\Models\HypervisorStatistic, OpenStack\Compute\v2\Models\Image, OpenStack\Compute\v2\Models\InstanceAction, OpenStack\Compute\v2\Models\Keypair, OpenStack\Compute\v2\Models\QuotaSet, OpenStack\Compute\v2\Models\Server, OpenStack\Identity\v2\Models\Catalog, OpenStack\Identity\v2\Models\Endpoint, OpenStack\Identity\v2\Models\Entry, OpenStack\Identity\v2\Models\Tenant, OpenStack\Identity\v2\Models\Token, OpenStack\Identity\v3\Models\Assignment, OpenStack\Identity\v3\Models\Catalog, OpenStack\Identity\v3\Models\Credential, OpenStack\Identity\v3\Models\Domain, OpenStack\Identity\v3\Models\Endpoint, OpenStack\Identity\v3\Models\Group, OpenStack\Identity\v3\Models\Policy, OpenStack\Identity\v3\Models\Project, OpenStack\Identity\v3\Models\Role, OpenStack\Identity\v3\Models\Service, OpenStack\Identity\v3\Models\Token, OpenStack\Identity\v3\Models\User, OpenStack\Images\v2\Models\Image, OpenStack\Images\v2\Models\Member, OpenStack\Metric\v1\Gnocchi\Models\Metric, OpenStack\Metric\v1\Gnocchi\Models\Resource, OpenStack\Metric\v1\Gnocchi\Models\ResourceType, OpenStack\Networking\v2\...ayer3\Models\FloatingIp, OpenStack\Networking\v2\...ns\Layer3\Models\Router, OpenStack\Networking\v2\...ps\Models\SecurityGroup, OpenStack\Networking\v2\...odels\SecurityGroupRule, OpenStack\Networking\v2\Models\InterfaceAttachment, OpenStack\Networking\v2\Models\LoadBalancer, OpenStack\Networking\v2\...adBalancerHealthMonitor, OpenStack\Networking\v2\...ls\LoadBalancerListener, OpenStack\Networking\v2\Models\LoadBalancerMember, OpenStack\Networking\v2\Models\LoadBalancerPool, OpenStack\Networking\v2\Models\LoadBalancerStat, OpenStack\Networking\v2\Models\LoadBalancerStatus, OpenStack\Networking\v2\Models\Network, OpenStack\Networking\v2\...s\NetworkIpAvailability, OpenStack\Networking\v2\Models\Port, OpenStack\Networking\v2\Models\Quota, OpenStack\Networking\v2\Models\Subnet, OpenStack\ObjectStore\v1\Models\Account, OpenStack\ObjectStore\v1\Models\Container, OpenStack\ObjectStore\v1\Models\Object.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
668
    }
669
670
    /**
671
     * Get a specific instance action
672
     *
673
     * @string The request ID of the instance action
674
     * @return InstanceAction
675
     */
676
    public function getInstanceAction(string $requestId): InstanceAction
677
    {
678
      $response = $this->execute($this->api->getInstanceAction(), ['id' => $this->id, 'requestId' => $requestId]);
679
680
      return $this->model(InstanceAction::class)->populateFromResponse($response);
681
    }
682
}
683