1# -*- coding: utf-8 -*- # 2# Copyright 2014 Google LLC. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Read and write properties for the CloudSDK.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import unicode_literals 20 21import enum 22import functools 23import multiprocessing 24import os 25import re 26import sys 27 28from googlecloudsdk.core import argv_utils 29from googlecloudsdk.core import config 30from googlecloudsdk.core import exceptions 31from googlecloudsdk.core.configurations import named_configs 32from googlecloudsdk.core.configurations import properties_file as prop_files_lib 33from googlecloudsdk.core.docker import constants as const_lib 34from googlecloudsdk.core.util import encoding 35from googlecloudsdk.core.util import http_proxy_types 36from googlecloudsdk.core.util import scaled_integer 37from googlecloudsdk.core.util import times 38 39import six 40 41# Try to parse the command line flags at import time to see if someone provided 42# the --configuration flag. If they did, this could affect the value of the 43# properties defined in that configuration. Since some libraries (like logging) 44# use properties at startup, we want to use the correct configuration for that. 45named_configs.FLAG_OVERRIDE_STACK.PushFromArgs(argv_utils.GetDecodedArgv()) 46 47_SET_PROJECT_HELP = """\ 48To set your project, run: 49 50 $ gcloud config set project PROJECT_ID 51 52or to unset it, run: 53 54 $ gcloud config unset project""" 55 56_VALID_PROJECT_REGEX = re.compile( 57 r'^' 58 # An optional domain-like component, ending with a colon, e.g., 59 # google.com: 60 r'(?:(?:[-a-z0-9]{1,63}\.)*(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?):)?' 61 # Followed by a required identifier-like component, for example: 62 # waffle-house match 63 # -foozle no match 64 # Foozle no match 65 # We specifically disallow project number, even though some GCP backends 66 # could accept them. 67 # We also allow a leading digit as some legacy project ids can have 68 # a leading digit. 69 r'(?:(?:[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?))' 70 r'$') 71 72_VALID_ENDPOINT_OVERRIDE_REGEX = re.compile( 73 r'^' 74 # require http or https for scheme 75 r'(?:https?)://' 76 # netlocation portion of address. can be any of 77 # - domain name 78 # - 'localhost' 79 # - ipv4 addr 80 # - ipv6 addr 81 r'(?:' # begin netlocation 82 # - domain name, e.g. 'test-foo.sandbox.googleapis.com', or 'localhost' 83 r'(?:[A-Z0-9](?:[A-Z0-9-.])+)|' 84 # - ipv4 85 r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' 86 # - ipv6 87 r'\[?[A-F0-9]*:[A-F0-9:]+\]?' 88 r')' # end netlocation 89 # optional port 90 r'(?::\d+)?' 91 # require trailing slash, fragment optional 92 r'(?:/|[/?]\S+/)' 93 r'$', 94 re.IGNORECASE) 95 96_PUBSUB_NOTICE_URL = ( 97 'https://cloud.google.com/functions/docs/writing/background#event_parameter' 98) 99 100 101def Stringize(value): 102 if isinstance(value, six.string_types): 103 return value 104 return str(value) 105 106 107def ExistingAbsoluteFilepathValidator(file_path): 108 """Checks to see if the file path exists and is an absolute path.""" 109 if file_path is None: 110 return 111 if not os.path.isfile(file_path): 112 raise InvalidValueError('The provided path must exist.') 113 if not os.path.isabs(file_path): 114 raise InvalidValueError('The provided path must be absolute.') 115 116 117def _LooksLikeAProjectName(project): 118 """Heuristics testing if a string looks like a project name, but an id.""" 119 120 if re.match(r'[-0-9A-Z]', project[0]): 121 return True 122 123 return any(c in project for c in ' !"\'') 124 125 126def _BooleanValidator(property_name, value): 127 """Validates boolean properties. 128 129 Args: 130 property_name: str, the name of the property 131 value: str | bool, the value to validate 132 133 Raises: 134 InvalidValueError: if value is not boolean 135 """ 136 accepted_strings = [ 137 'true', '1', 'on', 'yes', 'y', 'false', '0', 'off', 'no', 'n', '', 'none' 138 ] 139 if Stringize(value).lower() not in accepted_strings: 140 raise InvalidValueError( 141 'The [{0}] value [{1}] is not valid. Possible values: [{2}]. ' 142 '(See http://yaml.org/type/bool.html)'.format( 143 property_name, value, 144 ', '.join([x if x else "''" for x in accepted_strings]))) 145 146 147def _BuildTimeoutValidator(timeout): 148 """Validates build timeouts.""" 149 if timeout is None: 150 return 151 seconds = times.ParseDuration(timeout, default_suffix='s').total_seconds 152 if seconds <= 0: 153 raise InvalidValueError('Timeout must be a positive time duration.') 154 155 156def _HumanReadableByteAmountValidator(size_string): 157 """Validates human readable byte amounts, e.g. 1KiB.""" 158 if size_string is None: 159 return 160 try: 161 scaled_integer.ParseInteger(size_string) 162 except ValueError as e: 163 raise InvalidValueError(str(e)) 164 165 166class Error(exceptions.Error): 167 """Exceptions for the properties module.""" 168 169 170class PropertiesParseError(Error): 171 """An exception to be raised when a properties file is invalid.""" 172 173 174class NoSuchPropertyError(Error): 175 """An exception to be raised when the desired property does not exist.""" 176 177 178class MissingInstallationConfig(Error): 179 """An exception to be raised when the sdk root does not exist.""" 180 181 def __init__(self): 182 super(MissingInstallationConfig, self).__init__( 183 'Installation properties could not be set because the installation ' 184 'root of the Cloud SDK could not be found.') 185 186 187class InvalidScopeValueError(Error): 188 """Exception for when a string could not be parsed to a valid scope value.""" 189 190 def __init__(self, given): 191 """Constructs a new exception. 192 193 Args: 194 given: str, The given string that could not be parsed. 195 """ 196 super(InvalidScopeValueError, self).__init__( 197 'Could not parse [{0}] into a valid configuration scope. ' 198 'Valid values are [{1}]'.format(given, 199 ', '.join(Scope.AllScopeNames()))) 200 201 202class InvalidValueError(Error): 203 """An exception to be raised when the set value of a property is invalid.""" 204 205 206class InvalidProjectError(InvalidValueError): 207 """An exception for bad project names, with a little user help.""" 208 209 def __init__(self, given): 210 super(InvalidProjectError, self).__init__(given + '\n' + _SET_PROJECT_HELP) 211 212 213class RequiredPropertyError(Error): 214 """Generic exception for when a required property was not set.""" 215 FLAG_STRING = ('It can be set on a per-command basis by re-running your ' 216 'command with the [{flag}] flag.\n\n') 217 218 def __init__(self, prop, flag=None, extra_msg=None): 219 if prop.section != VALUES.default_section.name: 220 section = prop.section + '/' 221 else: 222 section = '' 223 224 flag = flag or prop.default_flag 225 if flag: 226 flag_msg = RequiredPropertyError.FLAG_STRING.format(flag=flag) 227 else: 228 flag_msg = '' 229 230 msg = ("""\ 231The required property [{property_name}] is not currently set. 232{flag_msg}You may set it for your current workspace by running: 233 234 $ gcloud config set {section}{property_name} VALUE 235 236or it can be set temporarily by the environment variable [{env_var}]""".format( 237 property_name=prop.name, 238 flag_msg=flag_msg, 239 section=section, 240 env_var=prop.EnvironmentName())) 241 if extra_msg: 242 msg += '\n\n' + extra_msg 243 super(RequiredPropertyError, self).__init__(msg) 244 self.property = prop 245 246 247class _Sections(object): 248 """Represents the available sections in the properties file. 249 250 Attributes: 251 access_context_manager: Section, The section containing access context 252 manager properties for the Cloud SDK. 253 accessibility: Section, The section containing accessibility properties for 254 the Cloud SDK. 255 ai: Section, The section containing ai properties for the Cloud SDK. 256 ai_platform: Section, The section containing ai platform properties for the 257 Cloud SDK. 258 api_client_overrides: Section, The section containing API client override 259 properties for the Cloud SDK. 260 api_endpoint_overrides: Section, The section containing API endpoint 261 override properties for the Cloud SDK. 262 app: Section, The section containing app properties for the Cloud SDK. 263 auth: Section, The section containing auth properties for the Cloud SDK. 264 billing: Section, The section containing billing properties for the Cloud 265 SDK. 266 builds: Section, The section containing builds properties for the Cloud SDK. 267 artifacts: Section, The section containing artifacts properties for the 268 Cloud SDK. 269 code: Section, The section containing local development properties for Cloud 270 SDK. 271 component_manager: Section, The section containing properties for the 272 component_manager. 273 composer: Section, The section containing composer properties for the Cloud 274 SDK. 275 compute: Section, The section containing compute properties for the Cloud 276 SDK. 277 container: Section, The section containing container properties for the 278 Cloud SDK. 279 context_aware: Section, The section containing context aware access 280 configurations for the Cloud SDK. 281 core: Section, The section containing core properties for the Cloud SDK. 282 ssh: Section, The section containing ssh-related properties. 283 scc: Section, The section containing scc properties for the Cloud SDK. 284 deploy: Secion, The secion containing cloud deploy related properties for 285 the Cloud SDK. 286 dataproc: Section, The section containing dataproc properties for the Cloud 287 SDK. 288 dataflow: Section, The section containing dataflow properties for the Cloud 289 SDK. 290 datafusion: Section, The section containing datafusion properties for the 291 Cloud SDK. 292 declarative: Section, The section containing properties for declarative 293 workflows in the Cloud SDK. 294 default_section: Section, The main section of the properties file (core). 295 deployment_manager: Section, The section containing deployment_manager 296 properties for the Cloud SDK. 297 devshell: Section, The section containing devshell properties for the Cloud 298 SDK. 299 diagnostics: Section, The section containing diagnostics properties for the 300 Cloud SDK. 301 emulator: Section, The section containing emulator properties for the Cloud 302 SDK. 303 eventarc: Section, The section containing eventarc properties for the Cloud 304 SDK. 305 experimental: Section, The section containing experimental properties for 306 the Cloud SDK. 307 filestore: Section, The section containing filestore properties for the 308 Cloud SDK. 309 functions: Section, The section containing functions properties for the 310 Cloud SDK. 311 game_services: Section, The section containing gameservices properties for 312 the Cloud SDK. 313 gcloudignore: Section, The section containing gcloudignore properties for 314 the Cloud SDK. 315 healthcare: Section, The section containing healthcare properties for the 316 Cloud SDK. 317 interactive: Section, The section containing interactive properties for the 318 Cloud SDK. 319 kuberun: Section, The section containing kuberun properties for the Cloud 320 SDK. 321 lifesciences: Section, The section containing lifesciencs properties for the 322 Cloud SDK. 323 media_asset: Section, the section containing mediaasset protperties for the 324 Cloud SDK. 325 memcache: Section, The section containing memcache properties for the Cloud 326 SDK. 327 metastore: Section, The section containing metastore properties for the 328 Cloud SDK. 329 metrics: Section, The section containing metrics properties for the Cloud 330 SDK. 331 ml_engine: Section, The section containing ml_engine properties for the 332 Cloud SDK. 333 notebooks: Section, The section containing notebook properties for the Cloud 334 SDK. 335 privateca: Section, The section containing privateca properties for the 336 Cloud SDK. 337 proxy: Section, The section containing proxy properties for the Cloud SDK. 338 pubsub: Section, The section containing pubsub properties for the Cloud SDK. 339 redis: Section, The section containing redis properties for the Cloud SDK. 340 run: Section, The section containing run properties for the Cloud SDK. 341 secrets: Section, The section containing secretmanager properties for the 342 Cloud SDK. 343 spanner: Section, The section containing spanner properties for the Cloud 344 SDK. 345 storage: Section, The section containing storage properties for the Cloud 346 SDK. 347 survey: Section, The section containing survey properties for the Cloud SDK. 348 test: Section, The section containing test properties for the Cloud SDK. 349 transport: Section, The section containing transport properties for the 350 Cloud SDK. 351 transcoder: Section, The section containing transcoder properties for the 352 Cloud SDK. 353 vmware: Section, The section containing vmware properties for the Cloud SDK. 354 workflows: Section, The section containing workflows properties for the 355 Cloud SDK. 356 """ 357 358 class _ValueFlag(object): 359 360 def __init__(self, value, flag): 361 self.value = value 362 self.flag = flag 363 364 def __init__(self): 365 self.access_context_manager = _SectionAccessContextManager() 366 self.accessibility = _SectionAccessibility() 367 self.ai = _SectionAi() 368 self.ai_platform = _SectionAiPlatform() 369 self.api_client_overrides = _SectionApiClientOverrides() 370 self.api_endpoint_overrides = _SectionApiEndpointOverrides() 371 self.app = _SectionApp() 372 self.artifacts = _SectionArtifacts() 373 self.auth = _SectionAuth() 374 self.billing = _SectionBilling() 375 self.builds = _SectionBuilds() 376 self.code = _SectionCode() 377 self.component_manager = _SectionComponentManager() 378 self.composer = _SectionComposer() 379 self.compute = _SectionCompute() 380 self.container = _SectionContainer() 381 self.context_aware = _SectionContextAware() 382 self.core = _SectionCore() 383 self.ssh = _SectionSsh() 384 self.scc = _SectionScc() 385 self.deploy = _SectionDeploy() 386 self.dataproc = _SectionDataproc() 387 self.dataflow = _SectionDataflow() 388 self.datafusion = _SectionDatafusion() 389 self.declarative = _SectionDeclarative() 390 self.deployment_manager = _SectionDeploymentManager() 391 self.devshell = _SectionDevshell() 392 self.diagnostics = _SectionDiagnostics() 393 self.emulator = _SectionEmulator() 394 self.eventarc = _SectionEventarc() 395 self.experimental = _SectionExperimental() 396 self.filestore = _SectionFilestore() 397 self.functions = _SectionFunctions() 398 self.game_services = _SectionGameServices() 399 self.gcloudignore = _SectionGcloudignore() 400 self.healthcare = _SectionHealthcare() 401 self.interactive = _SectionInteractive() 402 self.kuberun = _SectionKubeRun() 403 self.lifesciences = _SectionLifeSciences() 404 self.media_asset = _SectionMediaAsset() 405 self.memcache = _SectionMemcache() 406 self.metastore = _SectionMetastore() 407 self.metrics = _SectionMetrics() 408 self.ml_engine = _SectionMlEngine() 409 self.notebooks = _SectionNotebooks() 410 self.privateca = _SectionPrivateCa() 411 self.proxy = _SectionProxy() 412 self.pubsub = _SectionPubsub() 413 self.redis = _SectionRedis() 414 self.run = _SectionRun() 415 self.secrets = _SectionSecrets() 416 self.spanner = _SectionSpanner() 417 self.storage = _SectionStorage() 418 self.survey = _SectionSurvey() 419 self.test = _SectionTest() 420 self.transport = _SectionTransport() 421 self.transcoder = _SectionTranscoder() 422 self.vmware = _SectionVmware() 423 self.workflows = _SectionWorkflows() 424 425 sections = [ 426 self.access_context_manager, 427 self.accessibility, 428 self.ai, 429 self.ai_platform, 430 self.api_client_overrides, 431 self.api_endpoint_overrides, 432 self.app, 433 self.auth, 434 self.billing, 435 self.builds, 436 self.artifacts, 437 self.code, 438 self.component_manager, 439 self.composer, 440 self.compute, 441 self.container, 442 self.context_aware, 443 self.core, 444 self.ssh, 445 self.scc, 446 self.dataproc, 447 self.dataflow, 448 self.datafusion, 449 self.deployment_manager, 450 self.devshell, 451 self.diagnostics, 452 self.emulator, 453 self.eventarc, 454 self.experimental, 455 self.filestore, 456 self.functions, 457 self.game_services, 458 self.gcloudignore, 459 self.healthcare, 460 self.interactive, 461 self.kuberun, 462 self.lifesciences, 463 self.media_asset, 464 self.memcache, 465 self.metastore, 466 self.metrics, 467 self.ml_engine, 468 self.notebooks, 469 self.pubsub, 470 self.privateca, 471 self.proxy, 472 self.redis, 473 self.run, 474 self.secrets, 475 self.spanner, 476 self.storage, 477 self.survey, 478 self.test, 479 self.transport, 480 self.transcoder, 481 self.vmware, 482 self.workflows, 483 ] 484 self.__sections = {section.name: section for section in sections} 485 self.__invocation_value_stack = [{}] 486 487 @property 488 def default_section(self): 489 return self.core 490 491 def __iter__(self): 492 return iter(self.__sections.values()) 493 494 def PushInvocationValues(self): 495 self.__invocation_value_stack.append({}) 496 497 def PopInvocationValues(self): 498 self.__invocation_value_stack.pop() 499 500 def SetInvocationValue(self, prop, value, flag): 501 """Set the value of this property for this command, using a flag. 502 503 Args: 504 prop: _Property, The property with an explicit value. 505 value: str, The value that should be returned while this command is 506 running. 507 flag: str, The flag that a user can use to set the property, reported if 508 it was required at some point but not set by the command line. 509 """ 510 value_flags = self.GetLatestInvocationValues() 511 if value: 512 prop.Validate(value) 513 value_flags[prop] = _Sections._ValueFlag(value, flag) 514 515 def GetLatestInvocationValues(self): 516 return self.__invocation_value_stack[-1] 517 518 def GetInvocationStack(self): 519 return self.__invocation_value_stack 520 521 def Section(self, section): 522 """Gets a section given its name. 523 524 Args: 525 section: str, The section for the desired property. 526 527 Returns: 528 Section, The section corresponding to the given name. 529 530 Raises: 531 NoSuchPropertyError: If the section is not known. 532 """ 533 try: 534 return self.__sections[section] 535 except KeyError: 536 raise NoSuchPropertyError( 537 'Section "{section}" does not exist.'.format(section=section)) 538 539 def AllSections(self, include_hidden=False): 540 """Gets a list of all registered section names. 541 542 Args: 543 include_hidden: bool, True to include hidden properties in the result. 544 545 Returns: 546 [str], The section names. 547 """ 548 return [ 549 name for name, value in six.iteritems(self.__sections) 550 if not value.is_hidden or include_hidden 551 ] 552 553 def AllValues(self, 554 list_unset=False, 555 include_hidden=False, 556 properties_file=None, 557 only_file_contents=False): 558 """Gets the entire collection of property values for all sections. 559 560 Args: 561 list_unset: bool, If True, include unset properties in the result. 562 include_hidden: bool, True to include hidden properties in the result. If 563 a property has a value set but is hidden, it will be included regardless 564 of this setting. 565 properties_file: PropertyFile, the file to read settings from. If None 566 the active property file will be used. 567 only_file_contents: bool, True if values should be taken only from the 568 properties file, false if flags, env vars, etc. should be consulted too. 569 Mostly useful for listing file contents. 570 571 Returns: 572 {str:{str:str}}, A dict of sections to dicts of properties to values. 573 """ 574 result = {} 575 for section in self: 576 section_result = section.AllValues( 577 list_unset=list_unset, 578 include_hidden=include_hidden, 579 properties_file=properties_file, 580 only_file_contents=only_file_contents) 581 if section_result: 582 result[section.name] = section_result 583 return result 584 585 def GetHelpString(self): 586 """Gets a string with the help contents for all properties and descriptions. 587 588 Returns: 589 str, The string for the man page section. 590 """ 591 messages = [] 592 sections = [self.default_section] 593 default_section_name = self.default_section.name 594 sections.extend( 595 sorted([ 596 s for name, s in six.iteritems(self.__sections) 597 if name != default_section_name and not s.is_hidden 598 ])) 599 for section in sections: 600 props = sorted([p for p in section if not p.is_hidden]) 601 if not props: 602 continue 603 messages.append('_{section}_::'.format(section=section.name)) 604 for prop in props: 605 messages.append('*{prop}*:::\n\n{text}'.format( 606 prop=prop.name, text=prop.help_text)) 607 return '\n\n\n'.join(messages) 608 609 610class _Section(object): 611 """Represents a section of the properties file that has related properties. 612 613 Attributes: 614 name: str, The name of the section. 615 is_hidden: bool, True if the section is hidden, False otherwise. 616 """ 617 618 def __init__(self, name, hidden=False): 619 self.__name = name 620 self.__is_hidden = hidden 621 self.__properties = {} 622 623 @property 624 def name(self): 625 return self.__name 626 627 @property 628 def is_hidden(self): 629 return self.__is_hidden 630 631 def __iter__(self): 632 return iter(self.__properties.values()) 633 634 def __hash__(self): 635 return hash(self.name) 636 637 def __eq__(self, other): 638 return self.name == other.name 639 640 def __ne__(self, other): 641 return self.name != other.name 642 643 def __gt__(self, other): 644 return self.name > other.name 645 646 def __ge__(self, other): 647 return self.name >= other.name 648 649 def __lt__(self, other): 650 return self.name < other.name 651 652 def __le__(self, other): 653 return self.name <= other.name 654 655 # pylint: disable=missing-docstring 656 def _Add(self, 657 name, 658 help_text=None, 659 internal=False, 660 hidden=False, 661 callbacks=None, 662 default=None, 663 validator=None, 664 choices=None, 665 completer=None, 666 default_flag=None): 667 prop = _Property( 668 section=self.__name, 669 name=name, 670 help_text=help_text, 671 internal=internal, 672 hidden=(self.is_hidden or hidden), 673 callbacks=callbacks, 674 default=default, 675 validator=validator, 676 choices=choices, 677 completer=completer, 678 default_flag=default_flag) 679 self.__properties[name] = prop 680 return prop 681 682 def _AddBool(self, 683 name, 684 help_text=None, 685 internal=False, 686 hidden=False, 687 callbacks=None, 688 default=None): 689 return self._Add( 690 name=name, 691 help_text=help_text, 692 internal=internal, 693 hidden=hidden, 694 callbacks=callbacks, 695 default=default, 696 validator=functools.partial(_BooleanValidator, name), 697 choices=('true', 'false')) 698 699 def Property(self, property_name): 700 """Gets a property from this section, given its name. 701 702 Args: 703 property_name: str, The name of the desired property. 704 705 Returns: 706 Property, The property corresponding to the given name. 707 708 Raises: 709 NoSuchPropertyError: If the property is not known for this section. 710 """ 711 try: 712 return self.__properties[property_name] 713 except KeyError: 714 raise NoSuchPropertyError('Section [{s}] has no property [{p}].'.format( 715 s=self.__name, p=property_name)) 716 717 def HasProperty(self, property_name): 718 """True iff section has given property. 719 720 Args: 721 property_name: str, The name of the property to check for membership. 722 723 Returns: 724 a boolean. True iff this section contains property_name. 725 """ 726 return property_name in self.__properties 727 728 def AllProperties(self, include_hidden=False): 729 """Gets a list of all registered property names in this section. 730 731 Args: 732 include_hidden: bool, True to include hidden properties in the result. 733 734 Returns: 735 [str], The property names. 736 """ 737 return [ 738 name for name, prop in six.iteritems(self.__properties) 739 if include_hidden or not prop.is_hidden 740 ] 741 742 def AllValues(self, 743 list_unset=False, 744 include_hidden=False, 745 properties_file=None, 746 only_file_contents=False): 747 """Gets all the properties and their values for this section. 748 749 Args: 750 list_unset: bool, If True, include unset properties in the result. 751 include_hidden: bool, True to include hidden properties in the result. If 752 a property has a value set but is hidden, it will be included regardless 753 of this setting. 754 properties_file: properties_file.PropertiesFile, the file to read settings 755 from. If None the active property file will be used. 756 only_file_contents: bool, True if values should be taken only from the 757 properties file, false if flags, env vars, etc. should be consulted too. 758 Mostly useful for listing file contents. 759 760 Returns: 761 {str:str}, The dict of {property:value} for this section. 762 """ 763 properties_file = ( 764 properties_file or named_configs.ActivePropertiesFile.Load()) 765 766 result = {} 767 for prop in self: 768 if prop.is_internal: 769 # Never show internal properties, ever. 770 continue 771 if (prop.is_hidden and not include_hidden and 772 _GetPropertyWithoutCallback(prop, properties_file) is None): 773 continue 774 775 if only_file_contents: 776 value = properties_file.Get(prop.section, prop.name) 777 else: 778 value = _GetPropertyWithoutDefault(prop, properties_file) 779 780 if value is None: 781 if not list_unset: 782 # Never include if not set and not including unset values. 783 continue 784 if prop.is_hidden and not include_hidden: 785 # If including unset values, exclude if hidden and not including 786 # hidden properties. 787 continue 788 789 # Always include if value is set (even if hidden) 790 result[prop.name] = value 791 return result 792 793 794class _SectionKubeRun(_Section): 795 """Contains the properties for the 'kuberun' section.""" 796 797 def __init__(self): 798 super(_SectionKubeRun, self).__init__('kuberun') 799 self.enable_experimental_commands = self._AddBool( 800 'enable_experimental_commands', 801 help_text='If True, experimental KubeRun commands will not prompt to ' 802 'continue.', 803 hidden=True) 804 805 self.environment = self._Add( 806 'environment', 807 help_text='If set, this environment will be used as the deployment' 808 'target in all KubeRun commands.', 809 hidden=True) 810 811 self.cluster = self._Add( 812 'cluster', 813 help_text='ID of the cluster or fully qualified identifier ' 814 'for the cluster', 815 hidden=True) 816 817 self.cluster_location = self._Add( 818 'cluster_location', 819 help_text='Zone or region in which the cluster is located.', 820 hidden=True) 821 822 self.use_kubeconfig = self._AddBool( 823 'use_kubeconfig', 824 help_text='Use the default or provided kubectl config file.', 825 hidden=True) 826 827 self.kubeconfig = self._Add( 828 'kubeconfig', 829 help_text='Absolute path to your kubectl config file.', 830 hidden=True) 831 832 self.context = self._Add( 833 'context', 834 help_text='Name of the context in your kubectl config file to use.', 835 hidden=True) 836 837 838class _SectionRun(_Section): 839 """Contains the properties for the 'run' section.""" 840 841 def __init__(self): 842 super(_SectionRun, self).__init__('run') 843 self.region = self._Add( 844 'region', 845 help_text='Default region to use when working with Cloud ' 846 'Run resources. When a `--region` flag is required ' 847 'but not provided, the command will fall back to this value, if set.') 848 849 self.namespace = self._Add( 850 'namespace', 851 help_text='Specific to working with Cloud on GKE or ' 852 'a Kubernetes cluster: Kubernetes namespace for the resource.', 853 hidden=True) 854 855 self.cluster = self._Add( 856 'cluster', 857 help_text='ID of the cluster or fully qualified identifier ' 858 'for the cluster') 859 860 self.cluster_location = self._Add( 861 'cluster_location', 862 help_text='Zone or region in which the cluster is located.') 863 864 self.platform = self._Add( 865 'platform', 866 choices=['gke', 'managed', 'kubernetes'], 867 help_text='Target platform for running commands.') 868 869 870class _SectionSecrets(_Section): 871 """Contains the properties for the 'secrets' section.""" 872 873 def __init__(self): 874 super(_SectionSecrets, self).__init__('secrets') 875 self.replication_policy = self._Add( 876 'replication-policy', 877 choices=['automatic', 'user-managed'], 878 help_text='The type of replication policy to apply to secrets. Allowed ' 879 'values are "automatic" and "user-managed". If user-managed then ' 880 'locations must also be provided.', 881 ) 882 self.locations = self._Add( 883 'locations', 884 help_text='A comma separated list of the locations to replicate ' 885 'secrets to. Only applies to secrets with a user-managed policy.') 886 887 888class _SectionSpanner(_Section): 889 """Contains the properties for the 'spanner' section.""" 890 891 def __init__(self): 892 super(_SectionSpanner, self).__init__('spanner') 893 self.instance = self._Add( 894 'instance', 895 help_text='Default instance to use when working with Cloud Spanner ' 896 'resources. When an instance is required but not provided by a flag, ' 897 'the command will fall back to this value, if set.', 898 completer='googlecloudsdk.command_lib.spanner.flags:InstanceCompleter') 899 900 901class _SectionCompute(_Section): 902 """Contains the properties for the 'compute' section.""" 903 904 def __init__(self): 905 super(_SectionCompute, self).__init__('compute') 906 self.zone = self._Add( 907 'zone', 908 help_text='Default zone to use when working with zonal Compute ' 909 'Engine resources. When a `--zone` flag is required but not provided, ' 910 'the command will fall back to this value, if set. To see valid ' 911 'choices, run `gcloud compute zones list`.', 912 completer=('googlecloudsdk.command_lib.compute.completers:' 913 'ZonesCompleter')) 914 self.region = self._Add( 915 'region', 916 help_text='Default region to use when working with regional Compute' 917 ' Engine resources. When a `--region` flag is required but not ' 918 'provided, the command will fall back to this value, if set. To see ' 919 'valid choices, run `gcloud compute regions list`.', 920 completer=('googlecloudsdk.command_lib.compute.completers:' 921 'RegionsCompleter')) 922 self.gce_metadata_read_timeout_sec = self._Add( 923 'gce_metadata_read_timeout_sec', 924 default=20, 925 help_text='Timeout of requesting data from gce metadata endpoints.', 926 hidden=True) 927 self.gce_metadata_check_timeout_sec = self._Add( 928 'gce_metadata_check_timeout_sec', 929 default=3, 930 help_text='Timeout of checking if it is on gce environment.', 931 hidden=True) 932 self.use_new_list_usable_subnets_api = self._AddBool( 933 'use_new_list_usable_subnets_api', 934 default=False, 935 help_text=( 936 'If True, use the new API for listing usable subnets which only ' 937 'returns subnets in the current project.')) 938 939 940class _SectionFunctions(_Section): 941 """Contains the properties for the 'functions' section.""" 942 943 def __init__(self): 944 super(_SectionFunctions, self).__init__('functions') 945 self.region = self._Add( 946 'region', 947 default='us-central1', 948 help_text='Default region to use when working with Cloud ' 949 'Functions resources. When a `--region` flag is required but not ' 950 'provided, the command will fall back to this value, if set. To see ' 951 'valid choices, run `gcloud beta functions regions list`.', 952 completer=('googlecloudsdk.command_lib.functions.flags:' 953 'LocationsCompleter')) 954 self.v2 = self._AddBool( 955 'v2', 956 default=False, 957 help_text='Default product version to use when working with Cloud ' 958 'Functions resources. When neither `--v2` nor `--no-v2` is provided, ' 959 'the decision of whether to use V2 falls back to this value.') 960 961 962class _SectionGcloudignore(_Section): 963 """Contains the properties for the 'gcloudignore' section.""" 964 965 def __init__(self): 966 super(_SectionGcloudignore, self).__init__('gcloudignore') 967 self.enabled = self._AddBool( 968 'enabled', 969 default=True, 970 help_text=( 971 'If True, do not upload `.gcloudignore` files (see `$ gcloud topic ' 972 'gcloudignore`). If False, turn off the gcloudignore mechanism ' 973 'entirely and upload all files.')) 974 975 976class _SectionHealthcare(_Section): 977 """Contains the properties for the 'healthcare' section.""" 978 979 def __init__(self): 980 super(_SectionHealthcare, self).__init__('healthcare') 981 self.location = self._Add( 982 'location', 983 default='us-central1', 984 help_text='Default location to use when working with Cloud Healthcare ' 985 'resources. When a `--location` flag is required but not provided, the ' 986 'command will fall back to this value.') 987 self.dataset = self._Add( 988 'dataset', 989 help_text='Default dataset to use when working with Cloud Healthcare ' 990 'resources. When a `--dataset` flag is required but not provided, the ' 991 'command will fall back to this value, if set.') 992 993 994class _SectionLifeSciences(_Section): 995 """Contains the properties for the 'lifesciences' section.""" 996 997 def __init__(self): 998 super(_SectionLifeSciences, self).__init__('lifesciences') 999 self.location = self._Add( 1000 'location', 1001 default='us-central1', 1002 help_text='Default location to use when working with Cloud Life Sciences ' 1003 'resources. When a `--location` flag is required but not provided, the ' 1004 'command will fall back to this value.') 1005 1006 1007class _SectionGameServices(_Section): 1008 """Contains the properties for the 'game_services' section.""" 1009 1010 def __init__(self): 1011 super(_SectionGameServices, self).__init__('game_services') 1012 self.deployment = self._Add( 1013 'default_deployment', 1014 default='-', 1015 help_text=('Default deployment to use when working with Cloud Game ' 1016 'Services list configs. When a --deployment flag is ' 1017 'required in a list command but not provided, the command ' 1018 'will fall back to this value which envokes aggregated ' 1019 'list from the backend.')) 1020 self.location = self._Add( 1021 'location', 1022 default='global', 1023 help_text=( 1024 'Default location to use when working with Cloud Game Services ' 1025 'resources. When a `--location` flag is required but not provided, ' 1026 'the command will fall back to this value.')) 1027 self.realm = self._Add( 1028 'default_realm', 1029 default='-', 1030 help_text=( 1031 'Default realm to use when working with Cloud Game Services list ' 1032 'clusters. When a --realm flag is required in a list command but ' 1033 'not provided, the command will fall back to this value which ' 1034 'envokes aggregated list from the backend.')) 1035 1036 1037class _SectionAccessibility(_Section): 1038 """Contains the properties for the 'accessibility' section.""" 1039 1040 def __init__(self): 1041 super(_SectionAccessibility, self).__init__('accessibility') 1042 self.screen_reader = self._AddBool( 1043 'screen_reader', 1044 default=False, 1045 help_text='Make gcloud more screen reader friendly.') 1046 1047 1048class _SectionApp(_Section): 1049 """Contains the properties for the 'app' section.""" 1050 1051 def __init__(self): 1052 super(_SectionApp, self).__init__('app') 1053 self.promote_by_default = self._AddBool( 1054 'promote_by_default', 1055 help_text='If True, when deploying a new version of a service, that ' 1056 'version will be promoted to receive all traffic for the service. ' 1057 'This property can be overridden via the `--promote-by-default` or ' 1058 '`--no-promote-by-default` flags.', 1059 default=True) 1060 self.stop_previous_version = self._AddBool( 1061 'stop_previous_version', 1062 help_text='If True, when deploying a new version of a service, the ' 1063 'previously deployed version is stopped. If False, older versions must ' 1064 'be stopped manually.', 1065 default=True) 1066 self.trigger_build_server_side = self._AddBool( 1067 'trigger_build_server_side', hidden=True, default=None) 1068 self.cloud_build_timeout = self._Add( 1069 'cloud_build_timeout', 1070 validator=_BuildTimeoutValidator, 1071 help_text='Timeout, in seconds, to wait for Docker builds to ' 1072 'complete during deployments. All Docker builds now use the ' 1073 'Cloud Build API.') 1074 self.container_builder_image = self._Add( 1075 'container_builder_image', 1076 default='gcr.io/cloud-builders/docker', 1077 hidden=True) 1078 self.use_appengine_api = self._AddBool( 1079 'use_appengine_api', default=True, hidden=True) 1080 # This property is currently ignored except on OS X Sierra or beta 1081 # deployments. 1082 # There's a theoretical benefit to exceeding the number of cores available, 1083 # since the task is bound by network/API latency among other factors, and 1084 # mini-benchmarks validated this (I got speedup from 4 threads to 8 on a 1085 # 4-core machine). 1086 self.num_file_upload_threads = self._Add( 1087 'num_file_upload_threads', default=None, hidden=True) 1088 1089 def GetRuntimeRoot(): 1090 sdk_root = config.Paths().sdk_root 1091 if sdk_root is None: 1092 return None 1093 else: 1094 return os.path.join(config.Paths().sdk_root, 'platform', 'ext-runtime') 1095 1096 self.runtime_root = self._Add( 1097 'runtime_root', callbacks=[GetRuntimeRoot], hidden=True) 1098 1099 # Whether or not to use the (currently under-development) Flex Runtime 1100 # Builders, as opposed to Externalized Runtimes. 1101 # True => ALWAYS 1102 # False => NEVER 1103 # Unset => default behavior, which varies between beta/GA commands 1104 self.use_runtime_builders = self._Add( 1105 'use_runtime_builders', 1106 default=None, 1107 help_text=('If set, opt in/out to a new code path for building ' 1108 'applications using pre-fabricated runtimes that can be ' 1109 'updated independently of client tooling. If not set, ' 1110 'the default path for each runtime is used.')) 1111 # The Cloud Storage path prefix for the Flex Runtime Builder configuration 1112 # files. The configuration files will live at 1113 # "<PREFIX>/<runtime>-<version>.yaml", with an additional 1114 # "<PREFIX>/runtime.version" indicating the latest version. 1115 self.runtime_builders_root = self._Add( 1116 'runtime_builders_root', default='gs://runtime-builders/', hidden=True) 1117 1118 1119class _SectionBuilds(_Section): 1120 """Contains the properties for the 'builds' section.""" 1121 1122 def __init__(self): 1123 super(_SectionBuilds, self).__init__('builds') 1124 1125 self.timeout = self._Add( 1126 'timeout', 1127 validator=_BuildTimeoutValidator, 1128 help_text='Timeout, in seconds, to wait for builds to complete. If ' 1129 'unset, defaults to 10 minutes.') 1130 self.check_tag = self._AddBool( 1131 'check_tag', 1132 default=True, 1133 hidden=True, 1134 help_text='If True, validate that the --tag value to builds ' 1135 'submit is in the gcr.io, *.gcr.io, or *.pkg.dev namespace.') 1136 # TODO(b/118509363): Remove this after its default is True. 1137 self.use_kaniko = self._AddBool( 1138 'use_kaniko', 1139 default=False, 1140 help_text='If True, kaniko will be used to build images described by ' 1141 'a Dockerfile, instead of `docker build`.') 1142 self.kaniko_cache_ttl = self._Add( 1143 'kaniko_cache_ttl', 1144 default=6, 1145 help_text='TTL, in hours, of cached layers when using Kaniko. If zero, ' 1146 'layer caching is disabled.') 1147 self.kaniko_image = self._Add( 1148 'kaniko_image', 1149 default='gcr.io/kaniko-project/executor:latest', 1150 hidden=True, 1151 help_text='Kaniko builder image to use when use_kaniko=True. Defaults ' 1152 'to gcr.io/kaniko-project/executor:latest') 1153 1154 1155class _SectionArtifacts(_Section): 1156 """Contains the properties for the 'artifacts' section.""" 1157 1158 def __init__(self): 1159 super(_SectionArtifacts, self).__init__('artifacts') 1160 1161 self.repository = self._Add( 1162 'repository', 1163 help_text='Default repository to use when working with Artifact ' 1164 'Registry resources. When a `repository` value is required but not ' 1165 'provided, the command will fall back to this value, if set.') 1166 1167 self.location = self._Add( 1168 'location', 1169 help_text='Default location to use when working with Artifact Registry ' 1170 'resources. When a `location` value is required but not provided, the ' 1171 'command will fall back to this value, if set. If this value is unset, ' 1172 'the default location is `global` when `location` value is optional.') 1173 1174 1175class _SectionContainer(_Section): 1176 """Contains the properties for the 'container' section.""" 1177 1178 def __init__(self): 1179 super(_SectionContainer, self).__init__('container') 1180 self.cluster = self._Add( 1181 'cluster', 1182 help_text='Name of the cluster to use by default when ' 1183 'working with Kubernetes Engine.') 1184 self.use_client_certificate = self._AddBool( 1185 'use_client_certificate', 1186 default=False, 1187 help_text='If True, use the cluster\'s client certificate to ' 1188 'authenticate to the cluster API server.') 1189 self.use_app_default_credentials = self._AddBool( 1190 'use_application_default_credentials', 1191 default=False, 1192 help_text='If True, use application default credentials to authenticate' 1193 ' to the cluster API server.') 1194 1195 self.build_timeout = self._Add( 1196 'build_timeout', 1197 validator=_BuildTimeoutValidator, 1198 help_text='Timeout, in seconds, to wait for container builds to ' 1199 'complete.') 1200 self.build_check_tag = self._AddBool( 1201 'build_check_tag', 1202 default=True, 1203 hidden=True, 1204 help_text='If True, validate that the --tag value to container builds ' 1205 'submit is in the gcr.io or *.gcr.io namespace.') 1206 1207 1208class _SectionCore(_Section): 1209 """Contains the properties for the 'core' section.""" 1210 1211 class InteractiveUXStyles(enum.Enum): 1212 NORMAL = 0 1213 OFF = 1 1214 TESTING = 2 1215 1216 def __init__(self): 1217 super(_SectionCore, self).__init__('core') 1218 self.account = self._Add( 1219 'account', 1220 help_text='Account `gcloud` should use for authentication. ' 1221 'Run `gcloud auth list` to see your currently available accounts.') 1222 self.disable_collection_path_deprecation_warning = self._AddBool( 1223 'disable_collection_path_deprecation_warning', 1224 hidden=True, 1225 help_text='If False, any usage of collection paths will result in ' 1226 'deprecation warning. Set it to False to disable it.') 1227 self.default_regional_backend_service = self._AddBool( 1228 'default_regional_backend_service', 1229 help_text='If True, backend services in `gcloud compute ' 1230 'backend-services` will be regional by default. Setting the `--global` ' 1231 'flag is required for global backend services.') 1232 self.disable_color = self._AddBool( 1233 'disable_color', 1234 help_text='If True, color will not be used when printing messages in ' 1235 'the terminal.') 1236 self.disable_command_lazy_loading = self._AddBool( 1237 'disable_command_lazy_loading', hidden=True) 1238 self.disable_prompts = self._AddBool( 1239 'disable_prompts', 1240 help_text='If True, the default answer will be assumed for all user ' 1241 'prompts. However, for any prompts that require user input, an error ' 1242 'will be raised. This is equivalent to either using the global ' 1243 '`--quiet` flag or setting the environment variable ' 1244 '`CLOUDSDK_CORE_DISABLE_PROMPTS` to 1. Setting this property is ' 1245 'useful when scripting with `gcloud`.') 1246 self.disable_usage_reporting = self._AddBool( 1247 'disable_usage_reporting', 1248 help_text='If True, anonymous statistics on SDK usage will not be ' 1249 'collected. This value is set by default based on your choices during ' 1250 'installation, but can be changed at any time. For more information, ' 1251 'see: https://cloud.google.com/sdk/usage-statistics') 1252 self.enable_gri = self._AddBool( 1253 'enable_gri', 1254 default=False, 1255 hidden=True, 1256 help_text='If True, the parser for gcloud Resource Identifiers will be' 1257 'enabled when interpreting resource arguments.') 1258 self.resource_completion_style = self._Add( 1259 'resource_completion_style', 1260 choices=('flags', 'gri'), 1261 default='flags', 1262 hidden=True, 1263 help_text='The resource completion style controls how resource strings ' 1264 'are represented in command argument completions. All styles, ' 1265 'including uri, are handled on input.') 1266 self.lint = self._Add( 1267 'lint', 1268 # Current runtime lint patterns. Delete from this comment when the 1269 # pattern usage has been deleted. 1270 # 1271 # AddCacheUpdaters: Throws an exception for each command that needs 1272 # a parser.display_info.AddCacheUpdater() call. 1273 # 1274 # When running tests set default=PATTERN[,PATTERN...] here to weed out 1275 # all occurrences of the patterns. Patterns are checked using substring 1276 # matching on the lint property string value: 1277 # 1278 # if 'AddCacheUpdaters' in properties.VALUES.core.lint.Get(): 1279 # # AddCacheUpdaters lint check enabled. 1280 default='none', 1281 hidden=True, 1282 help_text='Enable the runtime linter for specific patterns. ' 1283 'Each occurrence of a runtime pattern raises an exception. ' 1284 'The pattern names are source specific. Consult the source for ' 1285 'details.') 1286 self.api_host = self._Add( 1287 'api_host', hidden=True, default='https://www.googleapis.com') 1288 self.verbosity = self._Add( 1289 'verbosity', 1290 help_text='Default logging verbosity for `gcloud` commands. This is ' 1291 'the equivalent of using the global `--verbosity` flag. Supported ' 1292 'verbosity levels: `debug`, `info`, `warning`, `error`, `critical`, ' 1293 'and `none`.') 1294 self.user_output_enabled = self._AddBool( 1295 'user_output_enabled', 1296 help_text='True, by default. If False, messages to the user and command' 1297 ' output on both standard output and standard error will be' 1298 ' suppressed.', 1299 default=True) 1300 self.interactive_ux_style = self._Add( 1301 'interactive_ux_style', 1302 help_text='How to display interactive UX elements like progress bars ' 1303 'and trackers.', 1304 hidden=True, 1305 default=_SectionCore.InteractiveUXStyles.NORMAL, 1306 choices=[x.name for x in list(_SectionCore.InteractiveUXStyles)]) 1307 self.log_http = self._AddBool( 1308 'log_http', 1309 help_text='If True, log HTTP requests and responses to the logs. ' 1310 'To see logs in the terminal, adjust `verbosity` settings. ' 1311 'Otherwise, logs are available in their respective log files.', 1312 default=False) 1313 self.log_http_redact_token = self._AddBool( 1314 'log_http_redact_token', 1315 help_text='If true, this prevents log_http from printing access tokens.' 1316 ' This property does not have effect unless log_http is true.', 1317 default=True, 1318 hidden=True) 1319 self.log_http_streaming_body = self._AddBool( 1320 'log_http_streaming_body', 1321 help_text='If True, log the streaming body instead of logging' 1322 ' the "<streaming body>" text. This flag results in reading the entire' 1323 ' response body in memory.' 1324 ' This property does not have effect unless log_http is true.', 1325 default=False, 1326 hidden=True) 1327 self.http_timeout = self._Add('http_timeout', hidden=True) 1328 self.check_gce_metadata = self._AddBool( 1329 'check_gce_metadata', hidden=True, default=True) 1330 self.print_completion_tracebacks = self._AddBool( 1331 'print_completion_tracebacks', 1332 hidden=True, 1333 help_text='If True, print actual completion exceptions with traceback ' 1334 'instead of the nice UX scrubbed exceptions.') 1335 self.print_unhandled_tracebacks = self._AddBool( 1336 'print_unhandled_tracebacks', hidden=True) 1337 self.print_handled_tracebacks = self._AddBool( 1338 'print_handled_tracebacks', hidden=True) 1339 self.trace_token = self._Add( 1340 'trace_token', 1341 help_text='Token used to route traces of service requests for ' 1342 'investigation of issues. This token will be provided by Google ' 1343 'support.') 1344 self.trace_email = self._Add('trace_email', hidden=True) 1345 self.trace_log = self._Add('trace_log', default=False, hidden=True) 1346 self.request_reason = self._Add('request_reason', hidden=True) 1347 self.pass_credentials_to_gsutil = self._AddBool( 1348 'pass_credentials_to_gsutil', 1349 default=True, 1350 help_text='If True, pass the configured Cloud SDK authentication ' 1351 'to gsutil.') 1352 self.api_key = self._Add( 1353 'api_key', 1354 hidden=True, 1355 help_text='If provided, this API key is attached to all outgoing ' 1356 'API calls.') 1357 self.should_prompt_to_enable_api = self._AddBool( 1358 'should_prompt_to_enable_api', 1359 default=True, 1360 hidden=True, 1361 help_text='If true, will prompt to enable an API if a command fails due' 1362 ' to the API not being enabled.') 1363 self.color_theme = self._Add( 1364 'color_theme', 1365 help_text='Color palette for output.', 1366 hidden=True, 1367 default='off', 1368 choices=['off', 'normal', 'testing']) 1369 self.use_legacy_flattened_format = self._AddBool( 1370 'use_legacy_flattened_format', 1371 hidden=True, 1372 default=False, 1373 help_text='If True, use legacy format for flattened() and text().' 1374 'Please note that this option will not be supported indefinitely.') 1375 1376 def ShowStructuredLogsValidator(show_structured_logs): 1377 if show_structured_logs is None: 1378 return 1379 if show_structured_logs not in ['always', 'log', 'terminal', 'never']: 1380 raise InvalidValueError(('show_structured_logs must be one of: ' 1381 '[always, log, terminal, never]')) 1382 1383 self.show_structured_logs = self._Add( 1384 'show_structured_logs', 1385 choices=['always', 'log', 'terminal', 'never'], 1386 default='never', 1387 hidden=False, 1388 validator=ShowStructuredLogsValidator, 1389 help_text="""\ 1390 Control when JSON-structured log messages for the current verbosity 1391 level (and above) will be written to standard error. If this property 1392 is disabled, logs are formatted as `text` by default. 1393 1394 Valid values are: 1395 * `never` - Log messages as text 1396 * `always` - Always log messages as JSON 1397 * `log` - Only log messages as JSON if stderr is a file 1398 * `terminal` - Only log messages as JSON if stderr is a terminal 1399 1400 If unset, default is `never`.""") 1401 1402 def MaxLogDaysValidator(max_log_days): 1403 if max_log_days is None: 1404 return 1405 try: 1406 if int(max_log_days) < 0: 1407 raise InvalidValueError('Max number of days must be at least 0') 1408 except ValueError: 1409 raise InvalidValueError('Max number of days must be an integer') 1410 1411 self.max_log_days = self._Add( 1412 'max_log_days', 1413 validator=MaxLogDaysValidator, 1414 help_text='Maximum number of days to retain log files before deleting.' 1415 ' If set to 0, turns off log garbage collection and does not delete log' 1416 ' files. If unset, the default is 30 days.', 1417 default='30') 1418 1419 self.disable_file_logging = self._AddBool( 1420 'disable_file_logging', 1421 default=False, 1422 help_text='If True, `gcloud` will not store logs to a file. This may ' 1423 'be useful if disk space is limited.') 1424 1425 self.custom_ca_certs_file = self._Add( 1426 'custom_ca_certs_file', 1427 validator=ExistingAbsoluteFilepathValidator, 1428 help_text='Absolute path to a custom CA cert file.') 1429 1430 def ProjectValidator(project): 1431 """Checks to see if the project string is valid.""" 1432 if project is None: 1433 return 1434 1435 if not isinstance(project, six.string_types): 1436 raise InvalidValueError('project must be a string') 1437 if project == '': # pylint: disable=g-explicit-bool-comparison 1438 raise InvalidProjectError('The project property is set to the ' 1439 'empty string, which is invalid.') 1440 if project.isdigit(): 1441 raise InvalidProjectError( 1442 'The project property must be set to a valid project ID, not the ' 1443 'project number [{value}]'.format(value=project)) 1444 1445 if _VALID_PROJECT_REGEX.match(project): 1446 return 1447 1448 if _LooksLikeAProjectName(project): 1449 raise InvalidProjectError( 1450 'The project property must be set to a valid project ID, not the ' 1451 'project name [{value}]'.format(value=project)) 1452 # Non heuristics for a better error message. 1453 raise InvalidProjectError( 1454 'The project property must be set to a valid project ID, ' 1455 '[{value}] is not a valid project ID.'.format(value=project)) 1456 1457 self.project = self._Add( 1458 'project', 1459 help_text='Project ID of the Cloud Platform project to operate on ' 1460 'by default. This can be overridden by using the global `--project` ' 1461 'flag.', 1462 validator=ProjectValidator, 1463 completer=('googlecloudsdk.command_lib.resource_manager.completers:' 1464 'ProjectCompleter'), 1465 default_flag='--project') 1466 self.credentialed_hosted_repo_domains = self._Add( 1467 'credentialed_hosted_repo_domains', hidden=True) 1468 1469 1470class _SectionSsh(_Section): 1471 """Contains SSH-related properties.""" 1472 1473 def __init__(self): 1474 super(_SectionSsh, self).__init__('ssh') 1475 self.putty_force_connect = self._AddBool( 1476 'putty_force_connect', 1477 default=True, # For backwards compatibility only. 1478 help_text='Whether or not `gcloud` should automatically accept new or ' 1479 'changed host keys when executing plink/pscp commands on Windows. ' 1480 'Defaults to True, but can be set to False to present these ' 1481 'interactive prompts to the user for host key checking.') 1482 self.verify_internal_ip = self._AddBool( 1483 'verify_internal_ip', 1484 default=True, 1485 help_text='Whether or not `gcloud` should perform an initial SSH ' 1486 'connection to verify an instance ID is correct when connecting via ' 1487 'its internal IP. Without this check, `gcloud` will simply connect to ' 1488 'the internal IP of the desired instance, which may be wrong if the ' 1489 'desired instance is in a different subnet but happens to share the ' 1490 'same internal IP as an instance in the current subnet. Defaults to ' 1491 'True.') 1492 1493 1494class _SectionDeclarative(_Section): 1495 """Contains the properties for the 'declarative' section.""" 1496 1497 def __init__(self): 1498 super(_SectionDeclarative, self).__init__('declarative') 1499 self.client = self._Add( 1500 'client_type', 1501 choices=['dcl', 'kcc'], 1502 help_text='Underlying declarative client library to use for declarative commands.', 1503 default='kcc') 1504 self.format = self._Add( 1505 'format', 1506 choices=['krm', 'terraform'], 1507 help_text='Declarative format to use for declarative commands.', 1508 default='krm') 1509 1510 1511class _SectionScc(_Section): 1512 """Contains the properties for the 'scc' section.""" 1513 1514 def __init__(self): 1515 super(_SectionScc, self).__init__('scc') 1516 self.organization = self._Add( 1517 'organization', 1518 help_text='Default organization `gcloud` should use for scc surface.') 1519 self.parent = self._Add( 1520 'parent', 1521 help_text='Default parent `gcloud` should use for scc surface.') 1522 1523 1524class _SectionAuth(_Section): 1525 """Contains the properties for the 'auth' section.""" 1526 DEFAULT_AUTH_HOST = 'https://accounts.google.com/o/oauth2/auth' 1527 DEFAULT_TOKEN_HOST = 'https://oauth2.googleapis.com/token' 1528 1529 def __init__(self): 1530 super(_SectionAuth, self).__init__('auth') 1531 self.auth_host = self._Add( 1532 'auth_host', hidden=True, default=self.DEFAULT_AUTH_HOST) 1533 self.disable_credentials = self._AddBool( 1534 'disable_credentials', 1535 default=False, 1536 help_text='If True, `gcloud` will not attempt to load any credentials ' 1537 'or authenticate any requests. This is useful when behind a proxy ' 1538 'that adds authentication to requests.') 1539 self.token_host = self._Add( 1540 'token_host', hidden=True, default=self.DEFAULT_TOKEN_HOST) 1541 self.disable_ssl_validation = self._AddBool( 1542 'disable_ssl_validation', hidden=True) 1543 self.client_id = self._Add( 1544 'client_id', hidden=True, default=config.CLOUDSDK_CLIENT_ID) 1545 self.client_secret = self._Add( 1546 'client_secret', 1547 hidden=True, 1548 default=config.CLOUDSDK_CLIENT_NOTSOSECRET) 1549 self.authority_selector = self._Add('authority_selector', hidden=True) 1550 self.authorization_token_file = self._Add( 1551 'authorization_token_file', hidden=True) 1552 self.credential_file_override = self._Add( 1553 'credential_file_override', hidden=True) 1554 self.impersonate_service_account = self._Add( 1555 'impersonate_service_account', 1556 help_text='After setting this property, all API requests will be made ' 1557 'as the given service account instead of the currently selected ' 1558 'account. This is done without needing to create, download, and ' 1559 'activate a key for the account. In order to perform operations as the ' 1560 'service account, your currently selected account must have an IAM ' 1561 'role that includes the iam.serviceAccounts.getAccessToken permission ' 1562 'for the service account. The roles/iam.serviceAccountTokenCreator ' 1563 'role has this permission or you may create a custom role.') 1564 self.disable_load_google_auth = self._AddBool( 1565 'disable_load_google_auth', 1566 default=False, 1567 hidden=True, 1568 help_text='Global switch to turn off loading credentials as ' 1569 'google-auth. Users can use it to switch back to the old ' 1570 'mode if google-auth breaks users.') 1571 self.opt_out_google_auth = self._AddBool( 1572 'opt_out_google_auth', 1573 default=False, 1574 hidden=True, 1575 help_text='A switch to disable google-auth for a surface or a command ' 1576 'group, in case there are some edge cases or google-auth ' 1577 'does not work for some surface.') 1578 self.disable_activate_service_account_google_auth = self._AddBool( 1579 'disable_activate_service_account_google_auth', 1580 default=False, 1581 hidden=True, 1582 help_text='True to have activate-service-account command fall back to ' 1583 'execute against oauth2client library.') 1584 1585 1586class _SectionBilling(_Section): 1587 """Contains the properties for the 'auth' section.""" 1588 1589 LEGACY = 'LEGACY' 1590 CURRENT_PROJECT = 'CURRENT_PROJECT' 1591 CURRENT_PROJECT_WITH_FALLBACK = 'CURRENT_PROJECT_WITH_FALLBACK' 1592 1593 def __init__(self): 1594 super(_SectionBilling, self).__init__('billing') 1595 1596 self.quota_project = self._Add( 1597 'quota_project', 1598 default=_SectionBilling.CURRENT_PROJECT, 1599 help_text="""\ 1600 Project that will be charged quota for the 1601 operations performed in `gcloud`. When unset, the default is 1602 [CURRENT_PROJECT]; this will charge quota against the currently set 1603 project for operations performed on it. Additionally, some existing 1604 APIs will continue to use a shared project for quota by default, when 1605 this property is unset. 1606 1607 If you need to operate on one project, but 1608 need quota against a different project, you can use this property to 1609 specify the alternate project.""") 1610 1611 1612class _SectionMetrics(_Section): 1613 """Contains the properties for the 'metrics' section.""" 1614 1615 def __init__(self): 1616 super(_SectionMetrics, self).__init__('metrics', hidden=True) 1617 self.environment = self._Add('environment', hidden=True) 1618 self.environment_version = self._Add('environment_version', hidden=True) 1619 self.command_name = self._Add('command_name', internal=True) 1620 1621 1622class _SectionComponentManager(_Section): 1623 """Contains the properties for the 'component_manager' section.""" 1624 1625 def __init__(self): 1626 super(_SectionComponentManager, self).__init__('component_manager') 1627 self.additional_repositories = self._Add( 1628 'additional_repositories', 1629 help_text='Comma separated list of additional repositories to check ' 1630 'for components. This property is automatically managed by the ' 1631 '`gcloud components repositories` commands.') 1632 self.disable_update_check = self._AddBool( 1633 'disable_update_check', 1634 help_text='If True, Cloud SDK will not automatically check for ' 1635 'updates.') 1636 self.fixed_sdk_version = self._Add('fixed_sdk_version', hidden=True) 1637 self.snapshot_url = self._Add('snapshot_url', hidden=True) 1638 # We need the original snapshot_url because snapshot_url may be 1639 # overwritten by users. Without original_snapshot_url, users can be trapped 1640 # to the overwritten snapshot_url even after it is unset. 1641 self.original_snapshot_url = self._Add( 1642 'original_snapshot_url', 1643 internal=True, 1644 hidden=True, 1645 help_text='Snapshot URL when this installation is firstly installed.', 1646 default='https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json' 1647 ) 1648 1649 1650class _SectionExperimental(_Section): 1651 """Contains the properties for gcloud experiments.""" 1652 1653 def __init__(self): 1654 super(_SectionExperimental, self).__init__('experimental', hidden=True) 1655 self.fast_component_update = self._AddBool( 1656 'fast_component_update', default=False) 1657 1658 1659class _SectionFilestore(_Section): 1660 """Contains the properties for the 'filestore' section.""" 1661 1662 def __init__(self): 1663 super(_SectionFilestore, self).__init__('filestore') 1664 self.location = self._Add( 1665 'location', 1666 help_text='Please use the `--location` flag or set the ' 1667 'filestore/zone or filestore/region property.') 1668 self.zone = self._Add( 1669 'zone', 1670 help_text='Default zone to use when working with Cloud Filestore ' 1671 'zones. When a `--zone` flag is required but not ' 1672 'provided, the command will fall back to this value, if set.') 1673 self.region = self._Add( 1674 'region', 1675 help_text='Default region to use when working with Cloud Filestore ' 1676 'regions. When a `--region` flag is required but not ' 1677 'provided, the command will fall back to this value, if set.') 1678 1679 1680class _SectionTest(_Section): 1681 """Contains the properties for the 'test' section.""" 1682 1683 def __init__(self): 1684 super(_SectionTest, self).__init__('test') 1685 self.results_base_url = self._Add('results_base_url', hidden=True) 1686 self.matrix_status_interval = self._Add( 1687 'matrix_status_interval', hidden=True) 1688 1689 1690class _SectionTransport(_Section): 1691 """Contains the properties for the 'transport' section.""" 1692 1693 def __init__(self): 1694 super(_SectionTransport, self).__init__('transport', hidden=True) 1695 self.disable_requests_override = self._AddBool( 1696 'disable_requests_override', 1697 default=False, 1698 hidden=True, 1699 help_text='Global switch to turn off using requests as a ' 1700 'transport. Users can use it to switch back to the old ' 1701 'mode if requests breaks users.') 1702 self.opt_out_requests = self._AddBool( 1703 'opt_out_requests', 1704 default=False, 1705 hidden=True, 1706 help_text='A switch to disable requests for a surface or a command ' 1707 'group.') 1708 1709 1710class _SectionMlEngine(_Section): 1711 """Contains the properties for the 'ml_engine' section.""" 1712 1713 def __init__(self): 1714 super(_SectionMlEngine, self).__init__('ml_engine') 1715 self.polling_interval = self._Add( 1716 'polling_interval', 1717 default=60, 1718 help_text=('Interval (in seconds) at which to poll logs from your ' 1719 'Cloud ML Engine jobs. Note that making it much faster than ' 1720 'the default (60) will quickly use all of your quota.')) 1721 self.local_python = self._Add( 1722 'local_python', 1723 default=None, 1724 help_text=('Full path to the Python interpreter to use for ' 1725 'Cloud ML Engine local predict/train jobs. If not ' 1726 'specified, the default path is the one to the Python ' 1727 'interpreter found on system `PATH`.')) 1728 1729 1730class _SectionNotebooks(_Section): 1731 """Contains the properties for the 'notebooks' section.""" 1732 1733 def __init__(self): 1734 super(_SectionNotebooks, self).__init__('notebooks') 1735 1736 self.location = self._Add( 1737 'location', 1738 help_text='Default location to use when working with Notebook ' 1739 'resources. When a `location` value is required but not provided, the ' 1740 'command will fall back to this value, if set.') 1741 1742 1743class _SectionPubsub(_Section): 1744 """Contains the properties for the 'pubsub' section.""" 1745 1746 def __init__(self): 1747 super(_SectionPubsub, self).__init__('pubsub') 1748 self.legacy_output = self._AddBool( 1749 'legacy_output', 1750 default=False, 1751 internal=True, 1752 hidden=True, 1753 help_text=('Use the legacy output for beta pubsub commands. The legacy ' 1754 'output from beta is being deprecated. This property will ' 1755 'eventually be removed.')) 1756 1757 1758class _SectionComposer(_Section): 1759 """Contains the properties for the 'composer' section.""" 1760 1761 def __init__(self): 1762 super(_SectionComposer, self).__init__('composer') 1763 self.location = self._Add( 1764 'location', 1765 help_text=( 1766 'Composer location to use. Each Composer location ' 1767 'constitutes an independent resource namespace constrained to ' 1768 'deploying environments into Compute Engine regions inside this ' 1769 'location. This parameter corresponds to the ' 1770 '/locations/<location> segment of the Composer resource URIs being ' 1771 'referenced.')) 1772 1773 1774class _SectionDeploy(_Section): 1775 """Contains the properties for the 'deploy' section.""" 1776 1777 def __init__(self): 1778 super(_SectionDeploy, self).__init__('deploy') 1779 self.region = self._Add( 1780 'region', 1781 help_text=( 1782 'Cloud Deploy region to use. Each Cloud Deploy ' 1783 'region constitutes an independent resource namespace constrained ' 1784 'to deploying instances into Compute Engine zones inside ' 1785 'the region.')) 1786 self.delivery_pipeline = self._Add( 1787 'delivery_pipeline', 1788 help_text=('Delivery Pipeline being managed by Cloud Deploy.')) 1789 1790 1791class _SectionDataflow(_Section): 1792 """Contains the properties for the 'dataflow' section.""" 1793 1794 def __init__(self): 1795 super(_SectionDataflow, self).__init__('dataflow') 1796 self.disable_public_ips = self._AddBool( 1797 'disable_public_ips', 1798 help_text='Specifies that Cloud Dataflow workers ' 1799 'must not use public IP addresses.', 1800 default=False) 1801 self.print_only = self._AddBool( 1802 'print_only', 1803 help_text='Prints the container spec to stdout. Does not save in ' 1804 'Google Cloud Storage.', 1805 default=False) 1806 self.enable_streaming_engine = self._AddBool( 1807 'enable_streaming_engine', 1808 help_text='Set this to true to enable Streaming Engine for the job.', 1809 default=False) 1810 1811 1812class _SectionDatafusion(_Section): 1813 """Contains the properties for the 'datafusion' section.""" 1814 1815 def __init__(self): 1816 super(_SectionDatafusion, self).__init__('datafusion') 1817 self.location = self._Add( 1818 'location', 1819 help_text=( 1820 'Datafusion location to use. Each Datafusion location ' 1821 'constitutes an independent resource namespace constrained to ' 1822 'deploying environments into Compute Engine regions inside this ' 1823 'location. This parameter corresponds to the ' 1824 '/locations/<location> segment of the Datafusion resource URIs being ' 1825 'referenced.')) 1826 1827 1828class _SectionDataproc(_Section): 1829 """Contains the properties for the 'ml_engine' section.""" 1830 1831 def __init__(self): 1832 super(_SectionDataproc, self).__init__('dataproc') 1833 self.region = self._Add( 1834 'region', 1835 help_text=( 1836 'Cloud Dataproc region to use. Each Cloud Dataproc ' 1837 'region constitutes an independent resource namespace constrained ' 1838 'to deploying instances into Compute Engine zones inside ' 1839 'the region.')) 1840 1841 1842class _SectionDeploymentManager(_Section): 1843 """Contains the properties for the 'deployment_manager' section.""" 1844 1845 def __init__(self): 1846 super(_SectionDeploymentManager, self).__init__('deployment_manager') 1847 self.glob_imports = self._AddBool( 1848 'glob_imports', 1849 default=False, 1850 help_text=( 1851 'Enable import path globbing. Uses glob patterns to match multiple ' 1852 'imports in a config file.')) 1853 1854 1855class _SectionInteractive(_Section): 1856 """Contains the properties for the 'interactive' section.""" 1857 1858 def __init__(self): 1859 super(_SectionInteractive, self).__init__('interactive') 1860 self.bottom_bindings_line = self._AddBool( 1861 'bottom_bindings_line', 1862 default=True, 1863 help_text='If True, display the bottom key bindings line.') 1864 self.bottom_status_line = self._AddBool( 1865 'bottom_status_line', 1866 default=False, 1867 help_text='If True, display the bottom status line.') 1868 self.completion_menu_lines = self._Add( 1869 'completion_menu_lines', 1870 default=4, 1871 help_text='Number of lines in the completion menu.') 1872 self.context = self._Add( 1873 'context', default='', help_text='Command context string.') 1874 self.debug = self._AddBool( 1875 'debug', 1876 default=False, 1877 hidden=True, 1878 help_text='If True, enable the debugging display.') 1879 self.fixed_prompt_position = self._Add( 1880 'fixed_prompt_position', 1881 default=False, 1882 help_text='If True, display the prompt at the same position.') 1883 self.help_lines = self._Add( 1884 'help_lines', 1885 default=10, 1886 help_text='Maximum number of help snippet lines.') 1887 self.hidden = self._AddBool( 1888 'hidden', 1889 default=False, 1890 help_text='If True, expose hidden commands/flags.') 1891 self.justify_bottom_lines = self._AddBool( 1892 'justify_bottom_lines', 1893 default=False, 1894 help_text='If True, left- and right-justify bottom toolbar lines.') 1895 self.manpage_generator = self._Add( 1896 'manpage_generator', 1897 default=True, 1898 help_text=('If True, use the manpage CLI tree generator for ' 1899 'unsupported commands.')) 1900 self.multi_column_completion_menu = self._AddBool( 1901 'multi_column_completion_menu', 1902 default=False, 1903 help_text='If True, display the completions as a multi-column menu.') 1904 self.obfuscate = self._AddBool( 1905 'obfuscate', 1906 default=False, 1907 hidden=True, 1908 help_text='If True, obfuscate status PII.') 1909 self.prompt = self._Add( 1910 'prompt', default='$ ', help_text='Command prompt string.') 1911 self.show_help = self._AddBool( 1912 'show_help', 1913 default=True, 1914 help_text='If True, show help as command args are being entered.') 1915 self.suggest = self._AddBool( 1916 'suggest', 1917 default=False, 1918 help_text='If True, add command line suggestions based on history.') 1919 1920 1921class _SectionPrivateCa(_Section): 1922 """Contains the properties for the 'privateca' section.""" 1923 1924 def __init__(self): 1925 super(_SectionPrivateCa, self).__init__('privateca') 1926 self.location = self._Add( 1927 'location', 1928 help_text='Default location to use when working with Private CA ' 1929 'resources. When a `--location` flag is required but not provided, the ' 1930 'command will fall back to this value, if set.', 1931 completer=('googlecloudsdk.command_lib.privateca.completers:' 1932 'LocationsCompleter')) 1933 1934 1935class _SectionProxy(_Section): 1936 """Contains the properties for the 'proxy' section.""" 1937 1938 def __init__(self): 1939 super(_SectionProxy, self).__init__('proxy') 1940 self.address = self._Add( 1941 'address', help_text='Hostname or IP address of proxy server.') 1942 self.port = self._Add( 1943 'port', help_text='Port to use when connected to the proxy server.') 1944 self.rdns = self._Add( 1945 'rdns', 1946 default=True, 1947 help_text='If True, DNS queries will not be performed ' 1948 'locally, and instead, handed to the proxy to resolve. This is default' 1949 ' behavior.') 1950 self.username = self._Add( 1951 'username', 1952 help_text='Username to use when connecting, if the proxy ' 1953 'requires authentication.') 1954 self.password = self._Add( 1955 'password', 1956 help_text='Password to use when connecting, if the proxy ' 1957 'requires authentication.') 1958 1959 valid_proxy_types = sorted(http_proxy_types.PROXY_TYPE_MAP.keys()) 1960 1961 def ProxyTypeValidator(proxy_type): 1962 if proxy_type is not None and proxy_type not in valid_proxy_types: 1963 raise InvalidValueError( 1964 'The proxy type property value [{0}] is not valid. ' 1965 'Possible values: [{1}].'.format(proxy_type, 1966 ', '.join(valid_proxy_types))) 1967 1968 self.proxy_type = self._Add( 1969 'type', 1970 help_text='Type of proxy being used. Supported proxy types are:' 1971 ' [{0}].'.format(', '.join(valid_proxy_types)), 1972 validator=ProxyTypeValidator, 1973 choices=valid_proxy_types) 1974 1975 self.use_urllib3_via_shim = self._AddBool( 1976 'use_urllib3_via_shim', 1977 default=False, 1978 hidden=True, 1979 help_text='If True, use `urllib3` to make requests via `httplib2shim`.') 1980 1981 1982class _SectionDevshell(_Section): 1983 """Contains the properties for the 'devshell' section.""" 1984 1985 def __init__(self): 1986 super(_SectionDevshell, self).__init__('devshell') 1987 self.image = self._Add( 1988 'image', hidden=True, default=const_lib.DEFAULT_DEVSHELL_IMAGE) 1989 self.metadata_image = self._Add( 1990 'metadata_image', hidden=True, default=const_lib.METADATA_IMAGE) 1991 1992 1993class _SectionDiagnostics(_Section): 1994 """Contains the properties for the 'diagnostics' section.""" 1995 1996 def __init__(self): 1997 super(_SectionDiagnostics, self).__init__('diagnostics', hidden=True) 1998 self.hidden_property_whitelist = self._Add( 1999 'hidden_property_whitelist', 2000 internal=True, 2001 help_text=('Comma separated list of hidden properties that should be ' 2002 'allowed by the hidden properties diagnostic.')) 2003 2004 2005class _SectionApiEndpointOverrides(_Section): 2006 """Contains the properties for the 'api-endpoint-overrides' section. 2007 2008 This overrides what endpoint to use when talking to the given API. 2009 """ 2010 2011 def __init__(self): 2012 super(_SectionApiEndpointOverrides, self).__init__( 2013 'api_endpoint_overrides', hidden=True) 2014 self.accessapproval = self._Add('accessapproval') 2015 self.accesscontextmanager = self._Add('accesscontextmanager') 2016 self.anthosevents = self._Add('anthosevents') 2017 self.aiplatform = self._Add('aiplatform') 2018 self.apigateway = self._Add('apigateway') 2019 self.apigee = self._Add('apigee') 2020 self.appengine = self._Add('appengine') 2021 self.assuredworkloads = self._Add('assuredworkloads') 2022 self.bigtableadmin = self._Add('bigtableadmin') 2023 self.binaryauthorization = self._Add('binaryauthorization') 2024 self.artifactregistry = self._Add('artifactregistry') 2025 self.categorymanager = self._Add('categorymanager') 2026 self.certificatemanager = self._Add('certificatemanager') 2027 self.cloudasset = self._Add('cloudasset') 2028 self.cloudbilling = self._Add('cloudbilling') 2029 self.cloudbuild = self._Add('cloudbuild') 2030 self.cloudcommerceconsumerprocurement = self._Add( 2031 'cloudcommerceconsumerprocurement') 2032 self.clouddebugger = self._Add('clouddebugger') 2033 self.clouddeploy = self._Add('clouddeploy') 2034 self.clouderrorreporting = self._Add('clouderrorreporting') 2035 self.cloudfunctions = self._Add('cloudfunctions') 2036 self.cloudidentity = self._Add('cloudidentity') 2037 self.cloudiot = self._Add('cloudiot') 2038 self.cloudkms = self._Add('cloudkms') 2039 self.cloudresourcemanager = self._Add('cloudresourcemanager') 2040 self.cloudresourcesearch = self._Add('cloudresourcesearch') 2041 self.cloudscheduler = self._Add('cloudscheduler') 2042 self.cloudtasks = self._Add('cloudtasks') 2043 self.composer = self._Add('composer') 2044 self.compute = self._Add('compute') 2045 self.container = self._Add('container') 2046 self.containeranalysis = self._Add('containeranalysis') 2047 self.datacatalog = self._Add('datacatalog') 2048 self.dataflow = self._Add('dataflow') 2049 self.datafusion = self._Add('datafusion') 2050 self.datamigration = self._Add('datamigration') 2051 self.datapol = self._Add('datapol') 2052 self.dataproc = self._Add('dataproc') 2053 self.datastore = self._Add('datastore') 2054 self.deploymentmanager = self._Add('deploymentmanager') 2055 self.discovery = self._Add('discovery') 2056 self.dns = self._Add('dns') 2057 self.domains = self._Add('domains') 2058 self.eventarc = self._Add('eventarc') 2059 self.events = self._Add('events') 2060 self.kubernetesedge = self._Add('kubernetesedge') 2061 self.file = self._Add('file') 2062 self.firestore = self._Add('firestore') 2063 self.gameservices = self._Add('gameservices') 2064 self.genomics = self._Add('genomics') 2065 self.gkehub = self._Add('gkehub') 2066 self.healthcare = self._Add('healthcare') 2067 self.iam = self._Add('iam') 2068 self.iamassist = self._Add('iamassist') 2069 self.kubernetespolicy = self._Add('kubernetespolicy') 2070 self.labelmanager = self._Add('labelmanager') 2071 self.language = self._Add('language') 2072 self.lifesciences = self._Add('lifesciences') 2073 self.logging = self._Add('logging') 2074 self.luxadmin = self._Add('luxadmin') 2075 self.managedidentities = self._Add('managedidentities') 2076 self.manager = self._Add('manager') 2077 self.mediaasset = self._Add('mediaasset') 2078 self.memcache = self._Add('memcache') 2079 self.metastore = self._Add('metastore') 2080 self.ml = self._Add('ml') 2081 self.monitoring = self._Add('monitoring') 2082 self.networkconnectivity = self._Add('networkconnectivity') 2083 self.networkmanagement = self._Add('networkmanagement') 2084 self.networkservices = self._Add('networkservices') 2085 self.networksecurity = self._Add('networksecurity') 2086 self.notebooks = self._Add('notebooks') 2087 self.ondemandscanning = self._Add('ondemandscanning') 2088 self.orgpolicy = self._Add('orgpolicy') 2089 self.osconfig = self._Add('osconfig') 2090 self.oslogin = self._Add('oslogin') 2091 self.policysimulator = self._Add('policysimulator') 2092 self.policytroubleshooter = self._Add('policytroubleshooter') 2093 self.privateca = self._Add('privateca') 2094 self.publicca = self._Add('publicca') 2095 self.pubsub = self._Add('pubsub') 2096 self.pubsublite = self._Add('pubsublite') 2097 self.recommender = self._Add('recommender') 2098 self.remotebuildexecution = self._Add('remotebuildexecution') 2099 self.replicapoolupdater = self._Add('replicapoolupdater') 2100 self.resourcesettings = self._Add('resourcesettings') 2101 self.runtimeconfig = self._Add('runtimeconfig') 2102 self.redis = self._Add('redis') 2103 self.run = self._Add('run') 2104 self.scc = self._Add('securitycenter') 2105 self.servicemanagement = self._Add('servicemanagement') 2106 self.serviceregistry = self._Add('serviceregistry') 2107 self.serviceusage = self._Add('serviceusage') 2108 self.source = self._Add('source') 2109 self.sourcerepo = self._Add('sourcerepo') 2110 self.secrets = self._Add('secretmanager') 2111 self.servicedirectory = self._Add('servicedirectory') 2112 self.spanner = self._Add('spanner') 2113 self.speech = self._Add('speech') 2114 self.sql = self._Add('sql') 2115 self.storage = self._Add('storage') 2116 self.testing = self._Add('testing') 2117 self.toolresults = self._Add('toolresults') 2118 self.tpu = self._Add('tpu') 2119 self.vision = self._Add('vision') 2120 self.vpcaccess = self._Add('vpcaccess') 2121 self.workflowexecutions = self._Add('workflowexecutions') 2122 self.workflows = self._Add('workflows') 2123 self.sddc = self._Add('sddc') 2124 2125 def EndpointValidator(self, value): 2126 """Checks to see if the endpoint override string is valid.""" 2127 if value is None: 2128 return 2129 if not _VALID_ENDPOINT_OVERRIDE_REGEX.match(value): 2130 raise InvalidValueError( 2131 'The endpoint_overrides property must be an absolute URI beginning ' 2132 'with http:// or https:// and ending with a trailing \'/\'. ' 2133 '[{value}] is not a valid endpoint override.'.format(value=value)) 2134 2135 def _Add(self, name): 2136 return super(_SectionApiEndpointOverrides, self)._Add( 2137 name, validator=self.EndpointValidator) 2138 2139 2140class _SectionApiClientOverrides(_Section): 2141 """Contains the properties for the 'api-client-overrides' section. 2142 2143 This overrides the API client version to use when talking to this API. 2144 """ 2145 2146 def __init__(self): 2147 super(_SectionApiClientOverrides, self).__init__( 2148 'api_client_overrides', hidden=True) 2149 self.appengine = self._Add('appengine') 2150 self.cloudidentity = self._Add('cloudidentity') 2151 self.compute = self._Add('compute') 2152 self.compute_alpha = self._Add('compute/alpha') 2153 self.compute_beta = self._Add('compute/beta') 2154 self.compute_v1 = self._Add('compute/v1') 2155 self.container = self._Add('container') 2156 self.luxadmin = self._Add('luxadmin') 2157 self.speech = self._Add('speech') 2158 self.sql = self._Add('sql') 2159 self.run = self._Add('run') 2160 self.scc = self._Add('securitycenter') 2161 2162 2163class _SectionEmulator(_Section): 2164 """Contains the properties for the 'emulator' section. 2165 2166 This is used to configure emulator properties for pubsub and datastore, such 2167 as host_port and data_dir. 2168 """ 2169 2170 def __init__(self): 2171 super(_SectionEmulator, self).__init__('emulator', hidden=True) 2172 self.datastore_data_dir = self._Add('datastore_data_dir') 2173 self.pubsub_data_dir = self._Add('pubsub_data_dir') 2174 self.datastore_host_port = self._Add( 2175 'datastore_host_port', default='localhost:8081') 2176 self.pubsub_host_port = self._Add( 2177 'pubsub_host_port', default='localhost:8085') 2178 self.bigtable_host_port = self._Add( 2179 'bigtable_host_port', default='localhost:8086') 2180 2181 2182def AccessPolicyValidator(policy): 2183 """Checks to see if the Access Policy string is valid.""" 2184 if policy is None: 2185 return 2186 if not policy.isdigit(): 2187 raise InvalidValueError( 2188 'The access_context_manager.policy property must be set ' 2189 'to the policy number, not a string.') 2190 2191 2192class _SectionAccessContextManager(_Section): 2193 """Contains the properties for the 'access_context_manager' section.""" 2194 2195 def OrganizationValidator(self, org): 2196 """Checks to see if the Organization string is valid.""" 2197 if org is None: 2198 return 2199 if not org.isdigit(): 2200 raise InvalidValueError( 2201 'The access_context_manager.organization property must be set ' 2202 'to the organization ID number, not a string.') 2203 2204 def __init__(self): 2205 super(_SectionAccessContextManager, self).__init__( 2206 'access_context_manager', hidden=True) 2207 2208 self.policy = self._Add( 2209 'policy', 2210 validator=AccessPolicyValidator, 2211 help_text=('ID of the policy resource to operate on. Can be found ' 2212 'by running the `access-context-manager policies list` ' 2213 'command.')) 2214 self.organization = self._Add( 2215 'organization', 2216 validator=self.OrganizationValidator, 2217 help_text=('Default organization cloud-bindings command group will ' 2218 'operate on.')) 2219 2220 2221class _SectionContextAware(_Section): 2222 """Contains the properties for the 'context_aware' section.""" 2223 2224 def __init__(self): 2225 super(_SectionContextAware, self).__init__('context_aware') 2226 self.use_client_certificate = self._AddBool( 2227 'use_client_certificate', 2228 help_text=('If True, use client certificate to authorize user ' 2229 'device using Context-aware access. Some services may not ' 2230 'support client certificate authorization. If a command ' 2231 'sends requests to such services, the client certificate ' 2232 'will not be validated. ' 2233 'Run `gcloud topic client-certificate` for list of services ' 2234 'supporting this feature.'), 2235 default=False) 2236 self.auto_discovery_file_path = self._Add( 2237 'auto_discovery_file_path', 2238 validator=ExistingAbsoluteFilepathValidator, 2239 help_text='File path for auto discovery configuration file.', 2240 hidden=True) 2241 2242 2243class _SectionEventarc(_Section): 2244 """Contains the properties for the 'eventarc' section.""" 2245 2246 def __init__(self): 2247 super(_SectionEventarc, self).__init__('eventarc') 2248 self.location = self._Add( 2249 'location', 2250 help_text='The default location to use when working with Eventarc ' 2251 "resources. This should be either ``global'' or one of the supported " 2252 'regions. When a `--location` flag is required but not provided, the ' 2253 'command will fall back to this value, if set.') 2254 2255 2256class _SectionMemcache(_Section): 2257 """Contains the properties for the 'memcache' section.""" 2258 2259 def __init__(self): 2260 super(_SectionMemcache, self).__init__('memcache') 2261 self.region = self._Add( 2262 'region', 2263 help_text='Default region to use when working with Cloud Memorystore ' 2264 'for Memcached resources. When a `region` is required but not provided ' 2265 'by a flag, the command will fall back to this value, if set.') 2266 2267 2268class _SectionMetastore(_Section): 2269 """Contains the properties for the 'metastore' section.""" 2270 2271 class Tier(enum.Enum): 2272 developer = 1 2273 enterprise = 3 2274 2275 def TierValidator(self, tier): 2276 if tier is None: 2277 return 2278 2279 if tier not in [x.name for x in list(_SectionMetastore.Tier)]: 2280 raise InvalidValueError( 2281 ('tier `{0}` must be one of: [developer, enterprise]'.format(tier))) 2282 2283 def __init__(self): 2284 super(_SectionMetastore, self).__init__('metastore') 2285 self.location = self._Add( 2286 'location', 2287 help_text='Default location to use when working with Dataproc ' 2288 'Metastore. When a `location` is required but not provided by a flag, ' 2289 'the command will fall back to this value, if set.') 2290 self.tier = self._Add( 2291 'tier', 2292 validator=self.TierValidator, 2293 help_text="""\ 2294 Default tier to use when creating Dataproc Metastore services. 2295 When a `tier` is required but not provided by a flag, 2296 the command will fall back to this value, if set. 2297 2298 Valid values are: 2299 * `developer` - The developer tier provides limited scalability 2300 and no fault tolerance. Good for low-cost proof-of-concept. 2301 * `enterprise` - The enterprise tier provides multi-zone high 2302 availability, and sufficient scalability for enterprise-level 2303 Dataproc Metastore workloads.""", 2304 choices=[x.name for x in list(_SectionMetastore.Tier)]) 2305 2306 2307class _SectionRedis(_Section): 2308 """Contains the properties for the 'redis' section.""" 2309 2310 def __init__(self): 2311 super(_SectionRedis, self).__init__('redis') 2312 self.region = self._Add( 2313 'region', 2314 help_text='Default region to use when working with Cloud ' 2315 'Memorystore for Redis resources. When a `region` is required but not ' 2316 'provided by a flag, the command will fall back to this value, if set.') 2317 2318 2319class _SectionStorage(_Section): 2320 """Contains the properties for the 'storage' section.""" 2321 2322 _CHECK_HASHES_HELP_TEXT = ("""\ 2323 'check_hashes' specifies how strictly to require integrity checking for 2324 downloaded data. Legal values are: 2325 2326 'if_fast_else_fail' - (default) Only integrity check if the digest 2327 will run efficiently (using compiled code), else fail the download. 2328 2329 'if_fast_else_skip' - Only integrity check if the server supplies a hash 2330 and the local digest computation will run quickly, else skip the check. 2331 2332 'always' - Always check download integrity regardless of possible 2333 performance costs. 2334 2335 'never' - Don't perform download integrity checks. This setting is 2336 not recommended except for special cases such as measuring download 2337 performance excluding time for integrity checking. 2338 2339 This option exists to assist users who wish to download a GCS composite 2340 object and are unable to install crcmod with the C-extension. CRC32c is 2341 the only available integrity check for composite objects, and without the 2342 C-extension, download performance can be significantly degraded by the 2343 digest computation. This option is ignored for daisy-chain copies, which 2344 don't compute hashes but instead (inexpensively) compare the cloud source 2345 and destination hashes.""") 2346 2347 MAXIMUM_DEFAULT_PROCESS_COUNT = 12 2348 DEFAULT_THREAD_COUNT = 4 2349 2350 DEFAULT_CHUNK_SIZE = 104857600 # 100 MB, or 1024 * 1024 * 100. 2351 DEFAULT_RESUMABLE_THRESHOLD = 8388608 # 8 MB, or 1024 * 1024 * 8. 2352 2353 def __init__(self): 2354 super(_SectionStorage, self).__init__('storage', hidden=True) 2355 self.check_hashes = self._Add( 2356 'check_hashes', 2357 default='if_fast_else_fail', 2358 help_text=self._CHECK_HASHES_HELP_TEXT, 2359 choices=('if_fast_else_fail', 'if_fast_else_skip', 'always', 'never')) 2360 2361 self.chunk_size = self._Add( 2362 'chunk_size', 2363 default=self.DEFAULT_CHUNK_SIZE, 2364 help_text='Chunk size used for uploading and downloading from ' 2365 'Cloud Storage.') 2366 2367 self.max_retries = self._Add( 2368 'max_retries', 2369 default=23, 2370 help_text='Max number of retries for operations like copy.') 2371 2372 self.max_retry_delay = self._Add( 2373 'max_retry_delay', 2374 default=32, 2375 help_text='Max second delay between retriable operations.') 2376 2377 self.process_count = self._Add( 2378 'process_count', 2379 default=min(multiprocessing.cpu_count(), 2380 self.MAXIMUM_DEFAULT_PROCESS_COUNT), 2381 help_text='The maximum number of processes parallel execution should ' 2382 'use. When process_count and thread_count are both 1, commands use ' 2383 'sequential execution.') 2384 2385 self.resumable_threshold = self._Add( 2386 'resumable_threshold', 2387 default=self.DEFAULT_RESUMABLE_THRESHOLD, 2388 help_text='File operations above this size in bytes will use resumable' 2389 ' instead of one-shot strategies. For example, a resumable download.') 2390 2391 self.sliced_object_download_component_size = self._Add( 2392 'sliced_object_download_component_size', 2393 default='200M', 2394 validator=_HumanReadableByteAmountValidator, 2395 help_text='Target size and upper bound for files to be sliced into.' 2396 ' Analogous to parallel_composite_upload_component_size.') 2397 2398 self.sliced_object_download_max_components = self._Add( 2399 'sliced_object_download_max_components', 2400 default=4, 2401 validator=_HumanReadableByteAmountValidator, 2402 help_text='Specifies the maximum number of slices to be used when' 2403 ' performing a sliced object download.') 2404 2405 self.sliced_object_download_threshold = self._Add( 2406 'sliced_object_download_threshold', 2407 default='150M', 2408 validator=_HumanReadableByteAmountValidator, 2409 help_text='Slice files larger than this value. Zero will block sliced' 2410 ' downloads. Analogous to parallel_composite_upload_threshold.') 2411 2412 self.thread_count = self._Add( 2413 'thread_count', 2414 default=self.DEFAULT_THREAD_COUNT, 2415 help_text='The number of threads parallel execution should use per ' 2416 'process. When process_count and thread_count are both 1, commands use ' 2417 'sequential execution.') 2418 2419 self.parallel_composite_upload_component_size = self._Add( 2420 'parallel_composite_upload_component_size', 2421 default='50M', 2422 validator=_HumanReadableByteAmountValidator, 2423 help_text='Specifies the ideal size of a component in bytes, which ' 2424 'will act as an upper bound to the size of the components if ' 2425 'ceil(file_size / parallel_composite_upload_component_size) is less ' 2426 'than the maximum number of objects the API allows composing at once. ' 2427 'Values can be provided either in bytes or as human-readable values ' 2428 '(e.g., "150M" to represent 150 mebibytes).') 2429 2430 self.parallel_composite_upload_threshold = self._Add( 2431 'parallel_composite_upload_threshold', 2432 default='0', 2433 validator=_HumanReadableByteAmountValidator, 2434 help_text='Specifies the maximum size of a file to upload in a single ' 2435 'stream. Files larger than this threshold will be partitioned into ' 2436 'component parts, uploaded in parallel, then composed into a single ' 2437 'object. The number of components will be the smaller of ' 2438 'ceil(file_size / parallel_composite_upload_component_size) and ' 2439 'the maximum number of objects the API allows composing at once. For ' 2440 'GCS this limit is 32. If this property is set to 0, then automatic ' 2441 'parallel uploads will never occur.') 2442 2443 self.tracker_files_directory = self._Add( 2444 'tracker_files_directory', 2445 default=os.path.join('~', '.config', 'gcloud', 'surface_data', 2446 'storage', 'tracker_files'), 2447 help_text='Directory path to tracker files for resumable operations.') 2448 2449 # TODO(b/109938541): Remove this after implementation seems stable. 2450 self.use_gsutil = self._AddBool( 2451 'use_gsutil', 2452 default=False, 2453 help_text='If True, use the deprecated upload implementation which ' 2454 'uses gsutil.') 2455 2456 self.use_threading_local = self._AddBool( 2457 'use_threading_local', 2458 default=True, 2459 help_text='If True, reuses some resource if they are already declared on' 2460 ' a thread. If False, creates duplicates of resources like API clients' 2461 ' on the same thread. Turning off can help with some bugs but will' 2462 ' hurt performance.') 2463 2464 2465class _SectionSurvey(_Section): 2466 """Contains the properties for the 'survey' section.""" 2467 2468 def __init__(self): 2469 super(_SectionSurvey, self).__init__('survey') 2470 self.disable_prompts = self._AddBool( 2471 'disable_prompts', 2472 default=False, 2473 help_text='If True, gcloud will not prompt you to take periodic usage ' 2474 'experience surveys.') 2475 2476 2477class _SectionTranscoder(_Section): 2478 """Contains the properties for the 'transcoder' section.""" 2479 2480 def __init__(self): 2481 super(_SectionTranscoder, self).__init__('transcoder', hidden=True) 2482 self.location = self._Add( 2483 'location', 2484 help_text=( 2485 'Transcoder location to use. This parameter corresponds to the ' 2486 '/locations/<location> segment of the Transcoder resource URIs ' 2487 'being referenced.')) 2488 2489 2490class _SectionWorkflows(_Section): 2491 """Contains the properties for the 'workflows' section.""" 2492 2493 def __init__(self): 2494 super(_SectionWorkflows, self).__init__('workflows', hidden=True) 2495 self.location = self._Add( 2496 'location', 2497 default='us-central1', 2498 help_text='The default region to use when working with Cloud ' 2499 'Workflows resources. When a `--location` flag is required ' 2500 'but not provided, the command will fall back to this value, if set.') 2501 2502 2503class _SectionAi(_Section): 2504 """Contains the properties for the command group 'ai' section.""" 2505 2506 def __init__(self): 2507 super(_SectionAi, self).__init__('ai') 2508 self.region = self._Add( 2509 'region', 2510 help_text='Default region to use when working with' 2511 'AI Platform resources. When a `--region` flag is required ' 2512 'but not provided, the command will fall back to this value, if set.') 2513 2514 2515class _SectionAiPlatform(_Section): 2516 """Contains the properties for the command group 'ai_platform' section.""" 2517 2518 def __init__(self): 2519 super(_SectionAiPlatform, self).__init__('ai_platform') 2520 self.region = self._Add( 2521 'region', 2522 help_text='Default region to use when working with AI Platform ' 2523 'Training and Prediction resources (currently for Prediction only). ' 2524 'It is ignored for training resources for now. The value should be ' 2525 'either `global` or one of the supported regions. When a `--region` ' 2526 'flag is required but not provided, the command will fall back to this ' 2527 'value, if set.') 2528 2529 2530class _SectionVmware(_Section): 2531 """Contains the properties for the 'vmware' section.""" 2532 2533 def __init__(self): 2534 super(_SectionVmware, self).__init__('vmware') 2535 2536 self.region = self._Add( 2537 'region', 2538 default='us-central1', 2539 help_text='Default region to use when working with VMware ' 2540 'Engine resources. When a `--region` ' 2541 'flag is required but not provided, the command will fall back to ' 2542 'this value, if set.') 2543 2544 self.node_type = self._Add( 2545 'node-type', 2546 default='c1-highmem-72-metal', 2547 hidden=True, 2548 help_text='Node type to use when creating a new cluster.') 2549 2550 2551class _SectionCode(_Section): 2552 """Contains the properties for the 'code' section.""" 2553 2554 def __init__(self): 2555 super(_SectionCode, self).__init__('code', hidden=True) 2556 2557 self.minikube_event_timeout = self._Add( 2558 'minikube_event_timeout', 2559 default='90s', 2560 hidden=True, 2561 help_text='Terminate the cluster start process if this amount of time ' 2562 'has passed since the last minikube event.') 2563 2564 self.minikube_path_override = self._Add( 2565 'minikube_paht_override', 2566 hidden=True, 2567 help_text='Location of minikube binary.') 2568 2569 self.skaffold_path_override = self._Add( 2570 'skaffold_path_override', 2571 hidden=True, 2572 help_text='Location of skaffold binary.') 2573 2574 2575class _SectionMediaAsset(_Section): 2576 """Contains the properties for the 'media_asset' section.""" 2577 2578 def __init__(self): 2579 super(_SectionMediaAsset, self).__init__('media_asset') 2580 self.location = self._Add( 2581 'location', 2582 default='us-central1', 2583 help_text=( 2584 'Default location to use when working with Cloud Media Asset ' 2585 'resources. When a `--location` flag is required but not provided, ' 2586 'the command will fall back to this value.')) 2587 2588 2589class _Property(object): 2590 """An individual property that can be gotten from the properties file. 2591 2592 Attributes: 2593 section: str, The name of the section the property appears in in the file. 2594 name: str, The name of the property. 2595 help_text: str, The man page help for what this property does. 2596 is_hidden: bool, True to hide this property from display for users that 2597 don't know about them. 2598 is_internal: bool, True to hide this property from display even if it is 2599 set. Internal properties are implementation details not meant to be set by 2600 users. 2601 callbacks: [func], A list of functions to be called, in order, if no value 2602 is found elsewhere. The result of a callback will be shown in when 2603 listing properties (if the property is not hidden). 2604 completer: [func], a completer function 2605 default: str, A final value to use if no value is found after the callbacks. 2606 The default value is never shown when listing properties regardless of 2607 whether the property is hidden or not. 2608 default_flag: default_flag name to include in RequiredPropertyError if 2609 property fails on Get. This can be used for flags that are tightly coupled 2610 with a property. 2611 validator: func(str), A function that is called on the value when .Set()'d 2612 or .Get()'d. For valid values, the function should do nothing. For invalid 2613 values, it should raise InvalidValueError with an explanation of why it 2614 was invalid. 2615 choices: [str], The allowable values for this property. This is included in 2616 the help text and used in tab completion. 2617 """ 2618 2619 def __init__(self, 2620 section, 2621 name, 2622 help_text=None, 2623 hidden=False, 2624 internal=False, 2625 callbacks=None, 2626 default=None, 2627 validator=None, 2628 choices=None, 2629 completer=None, 2630 default_flag=None): 2631 self.__section = section 2632 self.__name = name 2633 self.__help_text = help_text 2634 self.__hidden = hidden 2635 self.__internal = internal 2636 self.__callbacks = callbacks or [] 2637 self.__default = default 2638 self.__validator = validator 2639 self.__choices = choices 2640 self.__completer = completer 2641 self.__default_flag = default_flag 2642 2643 @property 2644 def section(self): 2645 return self.__section 2646 2647 @property 2648 def name(self): 2649 return self.__name 2650 2651 @property 2652 def help_text(self): 2653 return self.__help_text 2654 2655 @property 2656 def is_hidden(self): 2657 return self.__hidden 2658 2659 @property 2660 def is_internal(self): 2661 return self.__internal 2662 2663 @property 2664 def default(self): 2665 return self.__default 2666 2667 @property 2668 def callbacks(self): 2669 return self.__callbacks 2670 2671 @property 2672 def choices(self): 2673 return self.__choices 2674 2675 @property 2676 def completer(self): 2677 return self.__completer 2678 2679 @property 2680 def default_flag(self): 2681 return self.__default_flag 2682 2683 def __hash__(self): 2684 return hash(self.section) + hash(self.name) 2685 2686 def __eq__(self, other): 2687 return self.section == other.section and self.name == other.name 2688 2689 def __ne__(self, other): 2690 return not self == other 2691 2692 def __gt__(self, other): 2693 return self.name > other.name 2694 2695 def __ge__(self, other): 2696 return self.name >= other.name 2697 2698 def __lt__(self, other): 2699 return self.name < other.name 2700 2701 def __le__(self, other): 2702 return self.name <= other.name 2703 2704 def GetOrFail(self): 2705 """Shortcut for Get(required=True). 2706 2707 Convinient as a callback function. 2708 2709 Returns: 2710 str, The value for this property. 2711 Raises: 2712 RequiredPropertyError if property is not set. 2713 """ 2714 2715 return self.Get(required=True) 2716 2717 def Get(self, required=False, validate=True): 2718 """Gets the value for this property. 2719 2720 Looks first in the environment, then in the workspace config, then in the 2721 global config, and finally at callbacks. 2722 2723 Args: 2724 required: bool, True to raise an exception if the property is not set. 2725 validate: bool, Whether or not to run the fetched value through the 2726 validation function. 2727 2728 Returns: 2729 str, The value for this property. 2730 """ 2731 value = _GetProperty(self, named_configs.ActivePropertiesFile.Load(), 2732 required) 2733 if validate: 2734 self.Validate(value) 2735 return value 2736 2737 def IsExplicitlySet(self): 2738 """Determines if this property has been explicitly set by the user. 2739 2740 Properties with defaults or callbacks don't count as explicitly set. 2741 2742 Returns: 2743 True, if the value was explicitly set, False otherwise. 2744 """ 2745 value = _GetPropertyWithoutCallback( 2746 self, named_configs.ActivePropertiesFile.Load()) 2747 return value is not None 2748 2749 def Validate(self, value): 2750 """Test to see if the value is valid for this property. 2751 2752 Args: 2753 value: str, The value of the property to be validated. 2754 2755 Raises: 2756 InvalidValueError: If the value was invalid according to the property's 2757 validator. 2758 """ 2759 if self.__validator: 2760 self.__validator(value) 2761 2762 def GetBool(self, required=False, validate=True): 2763 """Gets the boolean value for this property. 2764 2765 Looks first in the environment, then in the workspace config, then in the 2766 global config, and finally at callbacks. 2767 2768 Does not validate by default because boolean properties were not previously 2769 validated, and startup functions rely on boolean properties that may have 2770 invalid values from previous installations 2771 2772 Args: 2773 required: bool, True to raise an exception if the property is not set. 2774 validate: bool, Whether or not to run the fetched value through the 2775 validation function. 2776 2777 Returns: 2778 bool, The boolean value for this property, or None if it is not set. 2779 2780 Raises: 2781 InvalidValueError: if value is not boolean 2782 """ 2783 value = _GetBoolProperty( 2784 self, 2785 named_configs.ActivePropertiesFile.Load(), 2786 required, 2787 validate=validate) 2788 return value 2789 2790 def GetInt(self, required=False, validate=True): 2791 """Gets the integer value for this property. 2792 2793 Looks first in the environment, then in the workspace config, then in the 2794 global config, and finally at callbacks. 2795 2796 Args: 2797 required: bool, True to raise an exception if the property is not set. 2798 validate: bool, Whether or not to run the fetched value through the 2799 validation function. 2800 2801 Returns: 2802 int, The integer value for this property. 2803 """ 2804 value = _GetIntProperty(self, named_configs.ActivePropertiesFile.Load(), 2805 required) 2806 if validate: 2807 self.Validate(value) 2808 return value 2809 2810 def Set(self, value): 2811 """Sets the value for this property as an environment variable. 2812 2813 Args: 2814 value: str/bool, The proposed value for this property. If None, it is 2815 removed from the environment. 2816 """ 2817 self.Validate(value) 2818 if value is not None: 2819 value = Stringize(value) 2820 encoding.SetEncodedValue(os.environ, self.EnvironmentName(), value) 2821 2822 def AddCallback(self, callback): 2823 """Adds another callback for this property.""" 2824 self.__callbacks.append(callback) 2825 2826 def RemoveCallback(self, callback): 2827 """Removess given callback for this property.""" 2828 self.__callbacks.remove(callback) 2829 2830 def EnvironmentName(self): 2831 """Get the name of the environment variable for this property. 2832 2833 Returns: 2834 str, The name of the correct environment variable. 2835 """ 2836 return 'CLOUDSDK_{section}_{name}'.format( 2837 section=self.__section.upper(), 2838 name=self.__name.upper(), 2839 ) 2840 2841 def __str__(self): 2842 return '{section}/{name}'.format(section=self.__section, name=self.__name) 2843 2844 2845VALUES = _Sections() 2846 2847 2848def FromString(property_string): 2849 """Gets the property object corresponding the given string. 2850 2851 Args: 2852 property_string: str, The string to parse. It can be in the format 2853 section/property, or just property if the section is the default one. 2854 2855 Returns: 2856 properties.Property, The property or None if it failed to parse to a valid 2857 property. 2858 """ 2859 section, prop = ParsePropertyString(property_string) 2860 if not prop: 2861 return None 2862 return VALUES.Section(section).Property(prop) 2863 2864 2865def ParsePropertyString(property_string): 2866 """Parses a string into a section and property name. 2867 2868 Args: 2869 property_string: str, The property string in the format section/property. 2870 2871 Returns: 2872 (str, str), The section and property. Both will be none if the input 2873 string is empty. Property can be None if the string ends with a slash. 2874 """ 2875 if not property_string: 2876 return None, None 2877 2878 if '/' in property_string: 2879 section, prop = tuple(property_string.split('/', 1)) 2880 else: 2881 section = None 2882 prop = property_string 2883 2884 section = section or VALUES.default_section.name 2885 prop = prop or None 2886 return section, prop 2887 2888 2889class _ScopeInfo(object): 2890 2891 # pylint: disable=redefined-builtin 2892 def __init__(self, id, description): 2893 self.id = id 2894 self.description = description 2895 2896 2897class Scope(object): 2898 """An enum class for the different types of property files that can be used.""" 2899 2900 INSTALLATION = _ScopeInfo( 2901 id='installation', 2902 description='The installation based configuration file applies to all ' 2903 'users on the system that use this version of the Cloud SDK. If the SDK ' 2904 'was installed by an administrator, you will need administrator rights ' 2905 'to make changes to this file.') 2906 USER = _ScopeInfo( 2907 id='user', 2908 description='The user based configuration file applies only to the ' 2909 'current user of the system. It will override any values from the ' 2910 'installation configuration.') 2911 2912 _ALL = [USER, INSTALLATION] 2913 _ALL_SCOPE_NAMES = [s.id for s in _ALL] 2914 2915 @staticmethod 2916 def AllValues(): 2917 """Gets all possible enum values. 2918 2919 Returns: 2920 [Scope], All the enum values. 2921 """ 2922 return list(Scope._ALL) 2923 2924 @staticmethod 2925 def AllScopeNames(): 2926 return list(Scope._ALL_SCOPE_NAMES) 2927 2928 @staticmethod 2929 def FromId(scope_id): 2930 """Gets the enum corresponding to the given scope id. 2931 2932 Args: 2933 scope_id: str, The scope id to parse. 2934 2935 Raises: 2936 InvalidScopeValueError: If the given value cannot be parsed. 2937 2938 Returns: 2939 OperatingSystemTuple, One of the OperatingSystem constants or None if the 2940 input is None. 2941 """ 2942 if not scope_id: 2943 return None 2944 for scope in Scope._ALL: 2945 if scope.id == scope_id: 2946 return scope 2947 raise InvalidScopeValueError(scope_id) 2948 2949 @staticmethod 2950 def GetHelpString(): 2951 return '\n\n'.join( 2952 ['*{0}*::: {1}'.format(s.id, s.description) for s in Scope.AllValues()]) 2953 2954 2955def PersistProperty(prop, value, scope=None): 2956 """Sets the given property in the properties file. 2957 2958 This function should not generally be used as part of normal program 2959 execution. The property files are user editable config files that they should 2960 control. This is mostly for initial setup of properties that get set during 2961 SDK installation. 2962 2963 Args: 2964 prop: properties.Property, The property to set. 2965 value: str, The value to set for the property. If None, the property is 2966 removed. 2967 scope: Scope, The config location to set the property in. If given, only 2968 this location will be updated and it is an error if that location does not 2969 exist. If not given, it will attempt to update the property in the 2970 first of the following places that exists: - the active named config - 2971 user level config It will never fall back to installation properties; 2972 you must use that scope explicitly to set that value. 2973 2974 Raises: 2975 MissingInstallationConfig: If you are trying to set the installation config, 2976 but there is not SDK root. 2977 """ 2978 prop.Validate(value) 2979 if scope == Scope.INSTALLATION: 2980 config.EnsureSDKWriteAccess() 2981 config_file = config.Paths().installation_properties_path 2982 if not config_file: 2983 raise MissingInstallationConfig() 2984 prop_files_lib.PersistProperty(config_file, prop.section, prop.name, value) 2985 named_configs.ActivePropertiesFile.Invalidate(mark_changed=True) 2986 else: 2987 active_config = named_configs.ConfigurationStore.ActiveConfig() 2988 active_config.PersistProperty(prop.section, prop.name, value) 2989 # Print message if value being set/unset is overridden by environment var 2990 # to prevent user confusion 2991 env_name = prop.EnvironmentName() 2992 override = encoding.GetEncodedValue(os.environ, env_name) 2993 if override: 2994 warning_message = ('WARNING: Property [{0}] is overridden ' 2995 'by environment setting [{1}={2}]\n') 2996 # Writing to sys.stderr because of circular dependency 2997 # in googlecloudsdk.core.log on properties 2998 sys.stderr.write(warning_message.format(prop.name, env_name, override)) 2999 3000 3001def _GetProperty(prop, properties_file, required): 3002 """Gets the given property. 3003 3004 If the property has a designated command line argument and args is provided, 3005 check args for the value first. If the corresponding environment variable is 3006 set, use that second. If still nothing, use the callbacks. 3007 3008 Args: 3009 prop: properties.Property, The property to get. 3010 properties_file: properties_file.PropertiesFile, An already loaded 3011 properties files to use. 3012 required: bool, True to raise an exception if the property is not set. 3013 3014 Raises: 3015 RequiredPropertyError: If the property was required but unset. 3016 3017 Returns: 3018 str, The value of the property, or None if it is not set. 3019 """ 3020 3021 flag_to_use = None 3022 3023 invocation_stack = VALUES.GetInvocationStack() 3024 if len(invocation_stack) > 1: 3025 # First item is the blank stack entry, second is from the user command args. 3026 first_invocation = invocation_stack[1] 3027 if prop in first_invocation: 3028 flag_to_use = first_invocation.get(prop).flag 3029 3030 value = _GetPropertyWithoutDefault(prop, properties_file) 3031 if value is not None: 3032 return Stringize(value) 3033 3034 # Still nothing, check the final default. 3035 if prop.default is not None: 3036 return Stringize(prop.default) 3037 3038 # Not set, throw if required. 3039 if required: 3040 raise RequiredPropertyError(prop, flag=flag_to_use) 3041 3042 return None 3043 3044 3045def _GetPropertyWithoutDefault(prop, properties_file): 3046 """Gets the given property without using a default. 3047 3048 If the property has a designated command line argument and args is provided, 3049 check args for the value first. If the corresponding environment variable is 3050 set, use that second. Next, return whatever is in the property file. Finally, 3051 use the callbacks to find values. Do not check the default value. 3052 3053 Args: 3054 prop: properties.Property, The property to get. 3055 properties_file: properties_file.PropertiesFile, An already loaded 3056 properties files to use. 3057 3058 Returns: 3059 str, The value of the property, or None if it is not set. 3060 """ 3061 # Try to get a value from args, env, or property file. 3062 value = _GetPropertyWithoutCallback(prop, properties_file) 3063 if value is not None: 3064 return Stringize(value) 3065 3066 # No value, try getting a value from the callbacks. 3067 for callback in prop.callbacks: 3068 value = callback() 3069 if value is not None: 3070 return Stringize(value) 3071 3072 return None 3073 3074 3075def _GetPropertyWithoutCallback(prop, properties_file): 3076 """Gets the given property without using a callback or default. 3077 3078 If the property has a designated command line argument and args is provided, 3079 check args for the value first. If the corresponding environment variable is 3080 set, use that second. Finally, return whatever is in the property file. Do 3081 not check for values in callbacks or defaults. 3082 3083 Args: 3084 prop: properties.Property, The property to get. 3085 properties_file: PropertiesFile, An already loaded properties files to use. 3086 3087 Returns: 3088 str, The value of the property, or None if it is not set. 3089 """ 3090 # Look for a value in the flags that were used on this command. 3091 invocation_stack = VALUES.GetInvocationStack() 3092 for value_flags in reversed(invocation_stack): 3093 if prop not in value_flags: 3094 continue 3095 value_flag = value_flags.get(prop, None) 3096 if not value_flag: 3097 continue 3098 if value_flag.value is not None: 3099 return Stringize(value_flag.value) 3100 3101 # Check the environment variable overrides. 3102 value = encoding.GetEncodedValue(os.environ, prop.EnvironmentName()) 3103 if value is not None: 3104 return Stringize(value) 3105 3106 # Check the property file itself. 3107 value = properties_file.Get(prop.section, prop.name) 3108 if value is not None: 3109 return Stringize(value) 3110 3111 return None 3112 3113 3114def _GetBoolProperty(prop, properties_file, required, validate=False): 3115 """Gets the given property in bool form. 3116 3117 Args: 3118 prop: properties.Property, The property to get. 3119 properties_file: properties_file.PropertiesFile, An already loaded 3120 properties files to use. 3121 required: bool, True to raise an exception if the property is not set. 3122 validate: bool, True to validate the value 3123 3124 Returns: 3125 bool, The value of the property, or None if it is not set. 3126 """ 3127 value = _GetProperty(prop, properties_file, required) 3128 if validate: 3129 _BooleanValidator(prop.name, value) 3130 if value is None or Stringize(value).lower() == 'none': 3131 return None 3132 return value.lower() in ['1', 'true', 'on', 'yes', 'y'] 3133 3134 3135def _GetIntProperty(prop, properties_file, required): 3136 """Gets the given property in integer form. 3137 3138 Args: 3139 prop: properties.Property, The property to get. 3140 properties_file: properties_file.PropertiesFile, An already loaded 3141 properties files to use. 3142 required: bool, True to raise an exception if the property is not set. 3143 3144 Returns: 3145 int, The integer value of the property, or None if it is not set. 3146 """ 3147 value = _GetProperty(prop, properties_file, required) 3148 if value is None: 3149 return None 3150 try: 3151 return int(value) 3152 except ValueError: 3153 raise InvalidValueError( 3154 'The property [{prop}] must have an integer value: [{value}]'.format( 3155 prop=prop, value=value)) 3156 3157 3158def GetMetricsEnvironment(): 3159 """Get the metrics environment. 3160 3161 Returns the property metrics/environment if set, if not, it tries to deduce if 3162 we're on some known platforms like devshell or GCE. 3163 3164 Returns: 3165 None, if no environment is set or found 3166 str, a string denoting the environment if one is set or found 3167 """ 3168 3169 environment = VALUES.metrics.environment.Get() 3170 if environment: 3171 return environment 3172 3173 # No explicit environment defined, try to deduce it. 3174 # pylint: disable=g-import-not-at-top 3175 from googlecloudsdk.core.credentials import devshell as c_devshell 3176 if c_devshell.IsDevshellEnvironment(): 3177 return 'devshell' 3178 3179 from googlecloudsdk.core.credentials import gce_cache 3180 if gce_cache.GetOnGCE(check_age=False): 3181 return 'GCE' 3182 3183 return None 3184