Passed
Push — develop ( ef97e9...11ccd2 )
by Nikolay
04:33
created

AzureCloud::provision()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 26
rs 9.8333
cc 3
nc 2
nop 0
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright © 2017-2024 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\Core\System\CloudProvisioning;
21
use MikoPBX\Core\System\Util;
22
use GuzzleHttp\Client;
23
use GuzzleHttp\Exception\GuzzleException;
24
25
class AzureCloud extends CloudProvider
26
{
27
    const CLOUD_NAME='AzureCloud';
28
29
    private Client $client;
30
31
    public function __construct()
32
    {
33
        $this->client = new Client(['timeout' => self::HTTP_TIMEOUT]);
34
    }
35
36
    /**
37
     * Performs the Azure Cloud provisioning using the Metadata Service.
38
     *
39
     * @return bool True if the provisioning was successful, false otherwise.
40
     */
41
    public function provision(): bool
42
    {
43
        $metadata = $this->retrieveInstanceMetadata();
44
        if ($metadata === null || $metadata['compute']['azEnvironment'] !== 'AzurePublicCloud') {
45
            // If metadata is null or the environment is not AzurePublicCloud, do not proceed with provisioning.
46
            Util::sysLogMsg(__CLASS__, "Not an Azure environment. Provisioning aborted.");
47
            return false;
48
        }
49
50
        // Extract machine name and external IP address from metadata
51
        $hostname = $metadata['compute']['name'] ?? '';
52
        $extIp = $metadata['network']['interface'][0]['ipv4']['ipAddress'][0]['publicIpAddress'] ?? '';
53
54
        // Update LAN settings with hostname and external IP address
55
        $this->updateLanSettings($hostname, $extIp);
56
57
        // Update SSH keys, if available
58
        $sshKeys = array_column($metadata['compute']['publicKeys'] ?? [], 'keyData');
59
        $this->updateSSHKeys(implode(PHP_EOL, $sshKeys));
60
61
        // Update SSH anf WEB password using some unique identifier from the metadata
62
        $vmId =$metadata['compute']['vmId'] ?? '';
63
        $this->updateSSHPassword($vmId);
64
        $this->updateWebPassword($vmId);
65
66
        return true;
67
    }
68
69
    /**
70
     * Retrieves Azure instance metadata.
71
     *
72
     * @return array|null The instance metadata or null if retrieval failed.
73
     *
74
     */
75
    private function retrieveInstanceMetadata(): ?array
76
    {
77
        try {
78
            $response = $this->client->request('GET', 'http://169.254.169.254/metadata/instance', [
79
                'query' => ['api-version' => '2020-09-01', 'format' => 'json'],
80
                'headers' => ['Metadata' => 'true']
81
            ]);
82
83
            if ($response->getStatusCode() == 200) {
84
                return json_decode($response->getBody()->getContents(), true);
85
            }
86
        } catch (GuzzleException $e) {
87
            Util::sysLogMsg(__CLASS__, "Failed to retrieve Azure instance metadata: " . $e->getMessage());
88
        }
89
90
        return null;
91
    }
92
}
93