1# --------------------------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for license information.
4# --------------------------------------------------------------------------------------------
5
6# pylint: disable=line-too-long,too-many-lines
7
8from azure.cli.core.commands import LongRunningOperation
9from azure.core.exceptions import HttpResponseError
10from azure.mgmt.servicefabricmanagedclusters.models import (
11    NodeType,
12    EndpointRangeDescription,
13    VMSSExtension,
14    VaultSecretGroup,
15    VaultCertificate,
16    SubResource,
17    NodeTypeActionParameters
18)
19
20from knack.log import get_logger
21
22logger = get_logger(__name__)
23
24
25# pylint:disable=too-many-locals,
26def create_node_type(cmd,
27                     client,
28                     resource_group_name,
29                     cluster_name,
30                     node_type_name,
31                     instance_count,
32                     primary=False,
33                     disk_size=None,
34                     disk_type=None,
35                     application_start_port=None,
36                     application_end_port=None,
37                     ephemeral_start_port=None,
38                     ephemeral_end_port=None,
39                     vm_size=None,
40                     vm_image_publisher=None,
41                     vm_image_offer=None,
42                     vm_image_sku=None,
43                     vm_image_version=None,
44                     capacity=None,
45                     placement_property=None,
46                     is_stateless=False,
47                     multiple_placement_groups=False):
48
49    #  set defult parameters
50    if disk_size is None:
51        disk_size = 100
52
53    if vm_size is None:
54        vm_size = "Standard_D2"
55
56    if vm_image_publisher is None:
57        vm_image_publisher = "MicrosoftWindowsServer"
58
59    if vm_image_offer is None:
60        vm_image_offer = "WindowsServer"
61
62    if vm_image_sku is None:
63        vm_image_sku = "2019-Datacenter"
64
65    if vm_image_version is None:
66        vm_image_version = "latest"
67
68    try:
69        new_node_type = NodeType(is_primary=primary,
70                                 vm_instance_count=int(instance_count),
71                                 data_disk_size_gb=disk_size,
72                                 data_disk_type=disk_type,
73                                 vm_size=vm_size,
74                                 vm_image_publisher=vm_image_publisher,
75                                 vm_image_offer=vm_image_offer,
76                                 vm_image_sku=vm_image_sku,
77                                 vm_image_version=vm_image_version,
78                                 capacities=capacity,
79                                 placement_properties=placement_property,
80                                 is_stateless=is_stateless,
81                                 multiple_placement_groups=multiple_placement_groups)
82
83        if application_start_port and application_end_port:
84            new_node_type.application_ports = EndpointRangeDescription(start_port=application_start_port,
85                                                                       end_port=application_end_port)
86
87        if ephemeral_start_port and ephemeral_end_port:
88            new_node_type.ephemeral_ports = EndpointRangeDescription(start_port=ephemeral_start_port,
89                                                                     end_port=ephemeral_end_port)
90
91        logger.info("Creating node type '%s'", node_type_name)
92        poller = client.node_types.begin_create_or_update(resource_group_name, cluster_name, node_type_name, new_node_type)
93        node_type = LongRunningOperation(cmd.cli_ctx)(poller)
94        return node_type
95    except HttpResponseError as ex:
96        logger.error("HttpResponseError: %s", ex)
97        raise
98
99
100def update_node_type(cmd,
101                     client,
102                     resource_group_name,
103                     cluster_name,
104                     node_type_name,
105                     instance_count=None,
106                     application_start_port=None,
107                     application_end_port=None,
108                     ephemeral_start_port=None,
109                     ephemeral_end_port=None,
110                     capacity=None,
111                     placement_property=None):
112    try:
113        node_type = client.node_types.get(resource_group_name, cluster_name, node_type_name)
114
115        if instance_count is not None:
116            node_type.vm_instance_count = instance_count
117
118        if application_start_port and application_end_port:
119            node_type.application_ports = EndpointRangeDescription(start_port=application_start_port,
120                                                                   end_port=application_end_port)
121
122        if ephemeral_start_port and ephemeral_end_port:
123            node_type.ephemeral_ports = EndpointRangeDescription(start_port=ephemeral_start_port,
124                                                                 end_port=ephemeral_end_port)
125
126        if capacity is not None:
127            node_type.capacities = capacity
128
129        if placement_property is not None:
130            node_type.placement_properties = placement_property
131
132        poller = client.node_types.begin_create_or_update(resource_group_name, cluster_name, node_type_name, node_type)
133        return LongRunningOperation(cmd.cli_ctx)(poller)
134    except HttpResponseError as ex:
135        logger.error("HttpResponseError: %s", ex)
136        raise
137
138
139def reimage_node(cmd,
140                 client,
141                 resource_group_name,
142                 cluster_name,
143                 node_type_name,
144                 node_name,
145                 force=False):
146    try:
147        nodes = [node_name] if isinstance(node_name, str) else node_name
148        action_parameters = NodeTypeActionParameters(nodes=nodes, force=force)
149        poller = client.node_types.begin_reimage(resource_group_name, cluster_name, node_type_name, parameters=action_parameters)
150        LongRunningOperation(cmd.cli_ctx, start_msg='Reimaging nodes', finish_msg='Nodes reimaged')(poller)
151    except HttpResponseError as ex:
152        logger.error("HttpResponseError: %s", ex)
153        raise
154
155
156def restart_node(cmd,
157                 client,
158                 resource_group_name,
159                 cluster_name,
160                 node_type_name,
161                 node_name,
162                 force=False):
163    try:
164        nodes = [node_name] if isinstance(node_name, str) else node_name
165        action_parameters = NodeTypeActionParameters(nodes=nodes, force=force)
166        poller = client.node_types.begin_restart(resource_group_name, cluster_name, node_type_name, parameters=action_parameters)
167        LongRunningOperation(cmd.cli_ctx, start_msg='Restarting nodes', finish_msg='Nodes restarted')(poller)
168    except HttpResponseError as ex:
169        logger.error("HttpResponseError: %s", ex)
170        raise
171
172
173def delete_node(cmd,
174                client,
175                resource_group_name,
176                cluster_name,
177                node_type_name,
178                node_name,
179                force=False):
180    try:
181        nodes = [node_name] if isinstance(node_name, str) else node_name
182        action_parameters = NodeTypeActionParameters(nodes=nodes, force=force)
183        poller = client.node_types.begin_delete_node(resource_group_name, cluster_name, node_type_name, parameters=action_parameters)
184        LongRunningOperation(cmd.cli_ctx, start_msg='Deleting nodes', finish_msg='Nodes deleted')(poller)
185    except HttpResponseError as ex:
186        logger.error("HttpResponseError: %s", ex)
187        raise
188
189
190def add_vm_extension(cmd,
191                     client,
192                     resource_group_name,
193                     cluster_name,
194                     node_type_name,
195                     extension_name,
196                     publisher,
197                     extension_type,
198                     type_handler_version,
199                     force_update_tag=None,
200                     auto_upgrade_minor_version=True,
201                     setting=None,
202                     protected_setting=None,
203                     provision_after_extension=None):
204    try:
205        node_type: NodeType = client.node_types.get(resource_group_name, cluster_name, node_type_name)
206
207        if node_type.vm_extensions is None:
208            node_type.vm_extensions = []
209
210        newExtension = VMSSExtension(name=extension_name,
211                                     publisher=publisher,
212                                     type=extension_type,
213                                     type_handler_version=type_handler_version,
214                                     force_update_tag=force_update_tag,
215                                     auto_upgrade_minor_version=auto_upgrade_minor_version,
216                                     settings=setting,
217                                     protected_settings=protected_setting,
218                                     provision_after_extensions=provision_after_extension)
219
220        node_type.vm_extensions.append(newExtension)
221
222        poller = client.node_types.begin_create_or_update(resource_group_name, cluster_name, node_type_name, node_type)
223        return LongRunningOperation(cmd.cli_ctx)(poller)
224    except HttpResponseError as ex:
225        logger.error("HttpResponseError: %s", ex)
226        raise
227
228
229def delete_vm_extension(cmd,
230                        client,
231                        resource_group_name,
232                        cluster_name,
233                        node_type_name,
234                        extension_name):
235    try:
236        node_type: NodeType = client.node_types.get(resource_group_name, cluster_name, node_type_name)
237
238        if node_type.vm_extensions is not None:
239            original_len = len(node_type.vm_extensions)
240            node_type.vm_extensions = list(filter(lambda x: x.name.lower() != extension_name.lower(), node_type.vm_extensions))
241            if original_len == len(node_type.vm_extensions):
242                raise 'Extension with name {} not found'.format(extension_name)
243
244        poller = client.node_types.begin_create_or_update(resource_group_name, cluster_name, node_type_name, node_type)
245        return LongRunningOperation(cmd.cli_ctx)(poller)
246    except HttpResponseError as ex:
247        logger.error("HttpResponseError: %s", ex)
248        raise
249
250
251def add_vm_secret(cmd,
252                  client,
253                  resource_group_name,
254                  cluster_name,
255                  node_type_name,
256                  source_vault_id,
257                  certificate_url,
258                  certificate_store):
259    try:
260        node_type: NodeType = client.node_types.get(resource_group_name, cluster_name, node_type_name)
261
262        if node_type.vm_secrets is None:
263            node_type.vm_secrets = []
264
265        vault = next((x for x in node_type.vm_secrets if x.source_vault.id.lower() == source_vault_id.lower()), None)
266
267        vault_certificate = VaultCertificate(certificate_store=certificate_store, certificate_url=certificate_url)
268        new_vault_secret_group = False
269        if vault is None:
270            new_vault_secret_group = True
271            source_vault = SubResource(id=source_vault_id)
272            vault = VaultSecretGroup(source_vault=source_vault, vault_certificates=[])
273
274        if vault.vault_certificates is None:
275            vault.vault_certificates = []
276
277        vault.vault_certificates.append(vault_certificate)
278
279        if new_vault_secret_group:
280            node_type.vm_secrets.append(vault)
281
282        poller = client.node_types.begin_create_or_update(resource_group_name, cluster_name, node_type_name, node_type)
283        return LongRunningOperation(cmd.cli_ctx)(poller)
284    except HttpResponseError as ex:
285        logger.error("HttpResponseError: %s", ex)
286        raise
287