Exemplo n.º 1
0
  def GetCluster(self, cluster_ref):
    """Get a running cluster.

    Args:
      cluster_ref: cluster Resource to describe.
    Returns:
      Cluster message.
    Raises:
      Error: if cluster cannot be found.
    """
    try:
      return self.client.projects_zones_clusters.Get(cluster_ref.Request())
    except apitools_exceptions.HttpError as error:
      api_error = util.GetError(error)
      if api_error.code != 404:
        raise api_error

    # Cluster couldn't be found, maybe user got zone wrong?
    try:
      clusters = self.ListClusters(cluster_ref.projectId).clusters
    except apitools_exceptions.HttpError as error:
      raise exceptions.HttpException(util.GetError(error))
    for cluster in clusters:
      if cluster.name == cluster_ref.clusterId:
        # User likely got zone wrong.
        raise util.Error(WRONG_ZONE_ERROR_MSG.format(
            error=api_error,
            name=cluster_ref.clusterId,
            wrong_zone=self.Zone(cluster_ref),
            zone=cluster.zone))
    # Couldn't find a cluster with that name.
    raise util.Error(NO_SUCH_CLUSTER_ERROR_MSG.format(
        error=api_error,
        name=cluster_ref.clusterId,
        project=cluster_ref.projectId))
Exemplo n.º 2
0
def PopulateMembership(ref, args, request):
    """Populate membership object with metadata read from the cluster.

  Args:
    ref: reference to the membership object.
    args: command line arguments.
    request: API request to be issued

  Returns:
    modified request
  """
    kubeconfig, context = GetKubeconfigAndContext(args)

    cmd = [
        'get', 'namespace', 'kube-system', '-o', 'jsonpath=\'{.metadata.uid}\''
    ]

    membership = GetMembership(ref)

    # Warn if kubectl is not installed.
    if not c_util.CheckKubectlInstalled():
        raise c_util.Error('kubectl not installed.')

    out, err, returncode = RunKubectl(kubeconfig, context, cmd, '')
    if returncode != 0:
        raise c_util.Error('Failed to get the UID of cluster: {0}'.format(err))

    uuid = out.replace("'", '')
    membership.name = uuid
    request.membershipId = membership.name
    request.membership = membership

    return request
Exemplo n.º 3
0
def PopulateMembership(ref, args, request):
    """Populate membership object with metadata read from the cluster.

  Args:
    ref: reference to the membership object.
    args: command line arguments.
    request: API request to be issued
  Returns:
    modified request
  """
    kubeconfig, context = GetKubeconfigAndContext(args)

    cmd = [
        'get', 'namespace', 'kube-system', '-o', 'jsonpath=\'{.metadata.uid}\''
    ]

    membership = GetMembership(ref)

    # Warn if kubectl is not installed and ask user to manually fill in
    # resource_id field.
    if not c_util.CheckKubectlInstalled():
        raise c_util.Error('kubectl not installed')

    out, err, returncode = RunKubectl(kubeconfig, context, cmd, '')
    if returncode != 0:
        raise c_util.Error('Failed to get the UID of cluster: {0}'.format(err))

    membership.name = out
    membership.endpoint = core_apis.GetMessagesModule(
        'gkehub', 'v1beta1').MembershipEndpoint(resourceId=out)
    request.membershipId = membership.name
    request.membership = membership
    args.membershipsId = membership.name

    return request
    def RemoveLabels(self, cluster_ref, remove_labels):
        """Removes labels from a cluster.

    Args:
      cluster_ref: cluster to update.
      remove_labels: labels to remove.
    Returns:
      Operation ref for label set operation.
    """
        clus = None
        try:
            clus = self.client.projects_zones_clusters.Get(
                self.messages.ContainerProjectsZonesClustersGetRequest(
                    projectId=cluster_ref.projectId,
                    zone=cluster_ref.zone,
                    clusterId=cluster_ref.clusterId))
        except apitools_exceptions.HttpError as error:
            api_error = exceptions.HttpException(error, util.HTTP_ERROR_FORMAT)
            if api_error.payload.status_code != 404:
                raise api_error

        clus_labels = {}
        if clus.resourceLabels:
            for item in clus.resourceLabels.additionalProperties:
                clus_labels[item.key] = str(item.value)

        # if clusLabels empty, nothing to do
        if not clus_labels:
            raise util.Error(
                NO_LABELS_ON_CLUSTER_ERROR_MSG.format(cluster=clus.name))

        for k in remove_labels:
            try:
                clus_labels.pop(k)
            except KeyError as error:
                # if at least one label not found on cluster, raise error
                raise util.Error(
                    NO_SUCH_LABEL_ERROR_MSG.format(cluster=clus.name, name=k))

        labels = self.messages.SetLabelsRequest.ResourceLabelsValue()
        for k, v in sorted(clus_labels.iteritems()):
            labels.additionalProperties.append(
                labels.AdditionalProperty(key=k, value=v))

        req = self.messages.SetLabelsRequest(
            resourceLabels=labels, labelFingerprint=clus.labelFingerprint)

        operation = self.client.projects_zones_clusters.ResourceLabels(
            self.messages.ContainerProjectsZonesClustersResourceLabelsRequest(
                clusterId=cluster_ref.clusterId,
                zone=cluster_ref.zone,
                projectId=cluster_ref.projectId,
                setLabelsRequest=req))
        return self.ParseOperation(operation.name)
    def WaitForOperation(self,
                         operation_ref,
                         message,
                         timeout_s=1200,
                         poll_period_s=5):
        """Poll container Operation until its status is done or timeout reached.

    Args:
      operation_ref: operation resource.
      message: str, message to display to user while polling.
      timeout_s: number, seconds to poll with retries before timing out.
      poll_period_s: number, delay in seconds between requests.

    Returns:
      Operation: the return value of the last successful operations.get
      request.

    Raises:
      Error: if the operation times out or finishes with an error.
    """
        detail_message = None
        with progress_tracker.ProgressTracker(
                message,
                autotick=True,
                detail_message_callback=lambda: detail_message):
            start_time = time.clock()
            while timeout_s > (time.clock() - start_time):
                try:
                    operation = self.GetOperation(operation_ref)
                    if self.IsOperationFinished(operation):
                        # Success!
                        log.info('Operation %s succeeded after %.3f seconds',
                                 operation, (time.clock() - start_time))
                        break
                    detail_message = operation.detail
                except apitools_exceptions.HttpError as error:
                    log.debug('GetOperation failed: %s', error)
                    # Keep trying until we timeout in case error is transient.
                    # TODO(user): add additional backoff if server is returning 500s
                time.sleep(poll_period_s)
        if not self.IsOperationFinished(operation):
            log.err.Print(
                'Timed out waiting for operation {0}'.format(operation))
            raise util.Error(
                'Operation [{0}] is still running'.format(operation))
        if self.GetOperationError(operation):
            raise util.Error('Operation [{0}] finished with error: {1}'.format(
                operation, self.GetOperationError(operation)))

        return operation
Exemplo n.º 6
0
def ParseCreateOptionsBase(args):
    flags.MungeBasicAuthFlags(args)
    if (args.IsSpecified('enable_cloud_endpoints')
            and properties.VALUES.container.new_scopes_behavior.GetBool()):
        raise util.Error(
            'Flag --[no-]enable-cloud-endpoints is not allowed if '
            'property container/ new_scopes_behavior is set to true.')
    flags.WarnForUnspecifiedAutorepair(args)
    cluster_ipv4_cidr = args.cluster_ipv4_cidr
    enable_master_authorized_networks = args.enable_master_authorized_networks
    return api_adapter.CreateClusterOptions(
        accelerators=args.accelerator,
        additional_zones=args.additional_zones,
        addons=args.addons,
        cluster_ipv4_cidr=cluster_ipv4_cidr,
        cluster_secondary_range_name=args.cluster_secondary_range_name,
        cluster_version=args.cluster_version,
        node_version=args.node_version,
        create_subnetwork=args.create_subnetwork,
        disk_type=args.disk_type,
        enable_autorepair=args.enable_autorepair,
        enable_autoscaling=args.enable_autoscaling,
        enable_autoupgrade=args.enable_autoupgrade,
        enable_cloud_endpoints=args.enable_cloud_endpoints,
        enable_cloud_logging=args.enable_cloud_logging,
        enable_cloud_monitoring=args.enable_cloud_monitoring,
        enable_ip_alias=args.enable_ip_alias,
        enable_kubernetes_alpha=args.enable_kubernetes_alpha,
        enable_legacy_authorization=args.enable_legacy_authorization,
        enable_master_authorized_networks=enable_master_authorized_networks,
        enable_network_policy=args.enable_network_policy,
        image_type=args.image_type,
        image=args.image,
        image_project=args.image_project,
        image_family=args.image_family,
        issue_client_certificate=args.issue_client_certificate,
        labels=args.labels,
        local_ssd_count=args.local_ssd_count,
        maintenance_window=args.maintenance_window,
        master_authorized_networks=args.master_authorized_networks,
        max_nodes=args.max_nodes,
        max_nodes_per_pool=args.max_nodes_per_pool,
        min_cpu_platform=args.min_cpu_platform,
        min_nodes=args.min_nodes,
        network=args.network,
        node_disk_size_gb=args.disk_size,
        node_labels=args.node_labels,
        node_locations=args.node_locations,
        node_machine_type=args.machine_type,
        node_taints=args.node_taints,
        num_nodes=args.num_nodes,
        password=args.password,
        preemptible=args.preemptible,
        scopes=args.scopes,
        service_account=args.service_account,
        services_ipv4_cidr=args.services_ipv4_cidr,
        services_secondary_range_name=args.services_secondary_range_name,
        subnetwork=args.subnetwork,
        tags=args.tags,
        user=args.username)
Exemplo n.º 7
0
    def Run(self, args):
        """This is what gets called when the user runs this command.

    Args:
      args: an argparse namespace. All the arguments that were provided to this
        command invocation.

    Raises:
      util.Error: if the cluster is unreachable or not running.
    """
        util.CheckKubectlInstalled()
        adapter = self.context['api_adapter']
        location_get = self.context['location_get']
        location = location_get(args)
        cluster_ref = adapter.ParseCluster(args.name, location)
        log.status.Print('Fetching cluster endpoint and auth data.')
        # Call DescribeCluster to get auth info and cache for next time
        cluster = adapter.GetCluster(cluster_ref)
        auth = cluster.masterAuth
        # TODO(b/70856999) Make this consistent with the checks in
        # api_lib/container/kubeconfig.py.
        missing_creds = not (auth and auth.clientCertificate
                             and auth.clientKey)
        if missing_creds and not util.ClusterConfig.UseGCPAuthProvider():
            raise util.Error(
                'get-credentials requires edit permission on {0}'.format(
                    cluster_ref.projectId))
        if not adapter.IsRunning(cluster):
            log.warning(NOT_RUNNING_MSG.format(cluster_ref.clusterId))
        util.ClusterConfig.Persist(cluster, cluster_ref.projectId,
                                   args.internal_ip)
Exemplo n.º 8
0
def GetUseV1APIProperty():
    """Returns whether v1 API should be used."""

    new_set = properties.VALUES.container.use_v1_api.IsExplicitlySet()
    if new_set:
        new_val = properties.VALUES.container.use_v1_api.GetBool()

    old_set = properties.VALUES.container.use_v1_api_client.IsExplicitlySet()
    if old_set:
        old_val = properties.VALUES.container.use_v1_api_client.GetBool()

    # use_v1_api is set but use_v1_api_client is not set
    if new_set and not old_set:
        return new_val
    # use_v1_api is not set but use_v1_api_client is set
    elif not new_set and old_set:
        return old_val
    # both use_v1_api and use_v1_api_client are not set
    elif not new_set and not old_set:
        # default behavior is using v1 api
        return True
    # both use_v1_api and use_v1_api_client are set
    else:
        # if the values of use_v1_api and use_v1_api match, return either one
        if new_val == old_val:
            return new_val
        else:
            raise util.Error(
                constants.
                CANNOT_SET_BOTH_USE_V1_API_PROPERTIES_WITH_DIFF_VALUES)
Exemplo n.º 9
0
    def Run(self, args):
        """This is what gets called when the user runs this command.

    Args:
      args: an argparse namespace. All the arguments that were provided to this
        command invocation.

    Raises:
      util.Error: if the cluster is unreachable or not running.
    """
        util.CheckKubectlInstalled()
        adapter = self.context['api_adapter']
        cluster_ref = adapter.ParseCluster(args.name)

        log.status.Print('Fetching cluster endpoint and auth data.')
        # Call DescribeCluster to get auth info and cache for next time
        cluster = adapter.GetCluster(cluster_ref)
        auth = cluster.masterAuth
        has_creds = (auth and ((auth.clientCertificate and auth.clientKey) or
                               (auth.username and auth.password)))
        if not has_creds and not util.ClusterConfig.UseGCPAuthProvider(
                cluster):
            raise util.Error(
                'get-credentials requires edit permission on {0}'.format(
                    cluster_ref.projectId))
        if not adapter.IsRunning(cluster):
            log.error(
                'cluster %s is not running. The kubernetes API will probably be '
                'unreachable.' % cluster_ref.clusterId)
        util.ClusterConfig.Persist(cluster, cluster_ref.projectId)
Exemplo n.º 10
0
def ParseCreateNodePoolOptionsBase(args):
    if (args.IsSpecified('enable_cloud_endpoints')
            and properties.VALUES.container.new_scopes_behavior.GetBool()):
        raise util.Error(
            'Flag --[no-]enable-cloud-endpoints is not allowed if '
            'property container/ new_scopes_behavior is set to true.')
    flags.WarnForUnspecifiedAutorepair(args)
    return api_adapter.CreateNodePoolOptions(
        accelerators=args.accelerator,
        machine_type=args.machine_type,
        disk_size_gb=args.disk_size,
        scopes=args.scopes,
        node_version=args.node_version,
        enable_cloud_endpoints=args.enable_cloud_endpoints,
        num_nodes=args.num_nodes,
        local_ssd_count=args.local_ssd_count,
        tags=args.tags,
        node_labels=args.node_labels,
        node_taints=args.node_taints,
        enable_autoscaling=args.enable_autoscaling,
        max_nodes=args.max_nodes,
        min_cpu_platform=args.min_cpu_platform,
        min_nodes=args.min_nodes,
        image_type=args.image_type,
        image=args.image,
        image_project=args.image_project,
        image_family=args.image_family,
        preemptible=args.preemptible,
        enable_autorepair=args.enable_autorepair,
        enable_autoupgrade=args.enable_autoupgrade,
        service_account=args.service_account,
        disk_type=args.disk_type)
Exemplo n.º 11
0
    def Run(self, args):
        """This is what gets called when the user runs this command.

    Args:
      args: an argparse namespace. All the arguments that were provided to this
        command invocation.

    Raises:
      util.Error: if the cluster is unreachable or not running.
    """
        util.CheckKubectlInstalled()
        adapter = self.context['api_adapter']
        location_get = self.context['location_get']
        location = location_get(args)
        cluster_ref = adapter.ParseCluster(args.name, location)
        if getattr(args, 'region', None):
            message = messages.NonGAFeatureUsingV1APIWarning(
                self._release_track)
            if message:
                console_io.PromptContinue(message=message, cancel_on_no=True)
        log.status.Print('Fetching cluster endpoint and auth data.')
        # Call DescribeCluster to get auth info and cache for next time
        cluster = adapter.GetCluster(cluster_ref)
        auth = cluster.masterAuth
        has_creds = (auth and ((auth.clientCertificate and auth.clientKey) or
                               (auth.username and auth.password)))
        if not has_creds and not util.ClusterConfig.UseGCPAuthProvider(
                cluster):
            raise util.Error(
                'get-credentials requires edit permission on {0}'.format(
                    cluster_ref.projectId))
        if not adapter.IsRunning(cluster):
            log.warn(NOT_RUNNING_MSG.format(cluster_ref.clusterId))
        util.ClusterConfig.Persist(cluster, cluster_ref.projectId)
Exemplo n.º 12
0
def GetKubeconfigAndContext(args):
    """Get kubeconfig and context of the cluster from arguments.

  Args:
    args: command line arguments

  Returns:
    the kubeconfig and context name

  Raises:
    calliope_exceptions.MinimumArgumentException: if $KUBECONFIG is not set and
      --kubeconfig is not provided.
    c_util.Error: if the context provided in args (or the current context in the
      kubeconfig file if a context is not provided) does not exist.
  """
    kubeconfig = args.kubeconfig_file or os.environ.get('KUBECONFIG')
    if not kubeconfig:
        raise calliope_exceptions.MinimumArgumentException([
            '--from-kubeconfig'
        ], 'Please specify kubeconfig or set $KUBECONFIG environment variable')
    kc = kconfig.Kubeconfig.LoadFromFile(kubeconfig)

    context_name = args.context
    if not context_name:
        context_name = kc.current_context

    if not kc.contexts[context_name]:
        raise c_util.Error(
            'context {0} does not exist in kubeconfig {1}'.format(
                context_name, kubeconfig))

    return kubeconfig, context_name
Exemplo n.º 13
0
  def WaitForComputeOperations(self, project, zone, operation_ids, message,
                               timeout_s=1200, poll_period_s=5):
    """Poll Compute Operations until their status is done or timeout reached.

    Args:
      project: project on which the operation is performed
      zone: zone on which the operation is performed
      operation_ids: list/set of ids of the compute operations to wait for
      message: str, message to display to user while polling.
      timeout_s: number, seconds to poll with retries before timing out.
      poll_period_s: number, delay in seconds between requests.

    Returns:
      Operations: list of the last successful operations.getrequest for each op.

    Raises:
      Error: if the operation times out or finishes with an error.
    """
    operation_ids = deque(operation_ids)
    operations = {}
    errors = []
    with console_io.ProgressTracker(message, autotick=True):
      start_time = time.clock()
      ops_to_retry = []
      while timeout_s > (time.clock() - start_time) and operation_ids:
        op_id = operation_ids.popleft()
        try:
          operation = self.GetComputeOperation(project, zone, op_id)
          operations[op_id] = operation
          if not self.IsComputeOperationFinished(operation):
            # Operation is still in progress.
            ops_to_retry.append(op_id)
            continue

          log.debug('Operation %s succeeded after %.3f seconds', operation,
                    (time.clock() - start_time))
          error = self.GetOperationError(operation)
          if error:
            # Operation Failed!
            msg = 'Operation [{0}] finished with error: {1}'.format(op_id,
                                                                    error)
            log.debug(msg)
            errors.append(msg)
        except apitools_exceptions.HttpError as error:
          log.debug('GetComputeOperation failed: %s', error)
          # Keep trying until we timeout in case error is transient.
          # TODO(user): add additional backoff if server is returning 500s
        if not operation_ids and ops_to_retry:
          operation_ids = deque(ops_to_retry)
          ops_to_retry = []
          time.sleep(poll_period_s)

    operation_ids.extend(ops_to_retry)
    for op_id in operation_ids:
      errors.append('Operation [{0}] is still running'.format(op_id))
    if errors:
      raise util.Error(linesep.join(errors))

    return operations.values()
Exemplo n.º 14
0
    def Run(self, args):
        """This is what gets called when the user runs this command.

    Args:
      args: an argparse namespace. All the arguments that were provided to this
        command invocation.

    Returns:
      Cluster message for the successfully created cluster.

    Raises:
      util.Error, if creation failed.
    """
        util.CheckKubectlInstalled()
        if not args.password:
            args.password = ''.join(
                random.SystemRandom().choice(string.ascii_letters +
                                             string.digits) for _ in range(16))

        adapter = self.context['api_adapter']

        if not args.scopes:
            args.scopes = []
        cluster_ref = adapter.ParseCluster(args.name)
        options = self.ParseCreateOptions(args)

        try:
            operation_ref = adapter.CreateCluster(cluster_ref, options)
            if not args.wait:
                return adapter.GetCluster(cluster_ref)

            adapter.WaitForOperation(operation_ref,
                                     'Creating cluster {0}'.format(
                                         cluster_ref.clusterId),
                                     timeout_s=args.timeout)
            cluster = adapter.GetCluster(cluster_ref)
        except apitools_base.HttpError as error:
            raise exceptions.HttpException(util.GetError(error))

        log.CreatedResource(cluster_ref)
        # Persist cluster config
        current_context = kconfig.Kubeconfig.Default().current_context
        c_config = util.ClusterConfig.Persist(cluster, cluster_ref.projectId,
                                              self.cli)
        if not c_config.has_certs:
            # Purge config so we retry the cert fetch on next kubectl command
            util.ClusterConfig.Purge(cluster.name, cluster.zone,
                                     cluster_ref.projectId)
            # reset current context
            if current_context:
                kubeconfig = kconfig.Kubeconfig.Default()
                kubeconfig.SetCurrentContext(current_context)
                kubeconfig.SaveToFile()
            raise util.Error(
                NO_CERTS_ERROR_FMT.format(
                    command=' '.join(args.command_path[:-1] +
                                     ['get-credentials', cluster.name])))
        return cluster
def _GetGKEKubeconfig(api_adapter, project, location_id, cluster_id,
                      temp_kubeconfig_dir, internal_ip,
                      cross_connect_subnetwork, private_endpoint_fqdn):
    """The kubeconfig of GKE Cluster is fetched using the GKE APIs.

  The 'KUBECONFIG' value in `os.environ` will be temporarily updated with
  the temporary kubeconfig's path if the kubeconfig arg is not None.
  Consequently, subprocesses started with
  googlecloudsdk.core.execution_utils.Exec will see the temporary KUBECONFIG
  environment variable.

  Using GKE APIs the GKE cluster is validated, and the ClusterConfig object, is
  persisted in the temporarily updated 'KUBECONFIG'.

  Args:
    api_adapter: the GKE api adapter used for running kubernetes commands
    project: string, the project id of the cluster for which kube config is to
      be fetched
    location_id: string, the id of the location to which the cluster belongs
    cluster_id: string, the id of the cluster
    temp_kubeconfig_dir: TemporaryDirectory object
    internal_ip: whether to persist the internal IP of the endpoint.
    cross_connect_subnetwork: full path of the cross connect subnet whose
      endpoint to persist (optional)
    private_endpoint_fqdn: whether to persist the private fqdn.

  Raises:
    Error: If unable to get credentials for kubernetes cluster.

  Returns:
    the path to the kubeconfig file
  """
    kubeconfig = os.path.join(temp_kubeconfig_dir.path, 'kubeconfig')
    old_kubeconfig = encoding.GetEncodedValue(os.environ, 'KUBECONFIG')
    try:
        encoding.SetEncodedValue(os.environ, 'KUBECONFIG', kubeconfig)
        if api_adapter is None:
            api_adapter = gke_api_adapter.NewAPIAdapter('v1')
        cluster_ref = api_adapter.ParseCluster(cluster_id, location_id,
                                               project)
        cluster = api_adapter.GetCluster(cluster_ref)
        auth = cluster.masterAuth
        valid_creds = auth and auth.clientCertificate and auth.clientKey
        # c_util.ClusterConfig.UseGCPAuthProvider() checks for
        # container/use_client_certificate setting
        if not valid_creds and not c_util.ClusterConfig.UseGCPAuthProvider():
            raise c_util.Error(
                'Unable to get cluster credentials. User must have edit '
                'permission on {}'.format(cluster_ref.projectId))
        c_util.ClusterConfig.Persist(cluster, cluster_ref.projectId,
                                     internal_ip, cross_connect_subnetwork,
                                     private_endpoint_fqdn)
    finally:
        if old_kubeconfig:
            encoding.SetEncodedValue(os.environ, 'KUBECONFIG', old_kubeconfig)
        else:
            del os.environ['KUBECONFIG']
    return kubeconfig
Exemplo n.º 16
0
  def CreateCluster(self, cluster_ref, options):
    node_config = self.messages.NodeConfig()
    if options.node_machine_type:
      node_config.machineType = options.node_machine_type
    if options.node_disk_size_gb:
      node_config.diskSizeGb = options.node_disk_size_gb
    if options.node_source_image:
      raise util.Error('cannot specify node source image in container v1 api')
    scope_uris = ExpandScopeURIs(options.scopes)
    if options.enable_cloud_endpoints:
      scope_uris += _ENDPOINTS_SCOPES
    node_config.oauthScopes = sorted(set(scope_uris + _REQUIRED_SCOPES))

    if options.local_ssd_count:
      node_config.localSsdCount = options.local_ssd_count

    if options.tags:
      node_config.tags = options.tags
    else:
      node_config.tags = []

    if options.image_family:
      node_config.imageFamily = options.image_family

    cluster = self.messages.Cluster(
        name=cluster_ref.clusterId,
        initialNodeCount=options.num_nodes,
        nodeConfig=node_config,
        masterAuth=self.messages.MasterAuth(username=options.user,
                                            password=options.password))
    if options.additional_zones:
      cluster.locations = options.additional_zones + [cluster_ref.zone]
    if options.cluster_version:
      cluster.initialClusterVersion = options.cluster_version
    if options.network:
      cluster.network = options.network
    if options.cluster_ipv4_cidr:
      cluster.clusterIpv4Cidr = options.cluster_ipv4_cidr
    if not options.enable_cloud_logging:
      cluster.loggingService = 'none'
    if not options.enable_cloud_monitoring:
      cluster.monitoringService = 'none'
    if options.subnetwork:
      cluster.subnetwork = options.subnetwork
    if options.disable_addons:
      addons = self._AddonsConfig(
          disable_ingress=INGRESS in options.disable_addons or None,
          disable_hpa=HPA in options.disable_addons or None)
      cluster.addonsConfig = addons

    create_cluster_req = self.messages.CreateClusterRequest(cluster=cluster)

    req = self.messages.ContainerProjectsZonesClustersCreateRequest(
        createClusterRequest=create_cluster_req,
        projectId=cluster_ref.projectId,
        zone=cluster_ref.zone)
    operation = self.client.projects_zones_clusters.Create(req)
    return self.ParseOperation(operation.name)
Exemplo n.º 17
0
    def UpdateCluster(self, cluster_ref, options):
        if not options.version:
            options.version = '-'
        if options.update_nodes:
            update = self.messages.ClusterUpdate(
                desiredNodeVersion=options.version,
                desiredNodePoolId=options.node_pool,
                desiredImageType=options.image_type)
        elif options.update_master:
            update = self.messages.ClusterUpdate(
                desiredMasterVersion=options.version)
        elif options.monitoring_service:
            update = self.messages.ClusterUpdate(
                desiredMonitoringService=options.monitoring_service)
        elif options.disable_addons:
            addons = self._AddonsConfig(
                disable_ingress=options.disable_addons.get(INGRESS),
                disable_hpa=options.disable_addons.get(HPA))
            update = self.messages.ClusterUpdate(desiredAddonsConfig=addons)
        elif options.enable_autoscaling is not None:
            # For update, we can either enable or disable.
            autoscaling = self.messages.NodePoolAutoscaling(
                enabled=options.enable_autoscaling)
            if options.enable_autoscaling:
                autoscaling.minNodeCount = options.min_nodes
                autoscaling.maxNodeCount = options.max_nodes
            update = self.messages.ClusterUpdate(
                desiredNodePoolId=options.node_pool,
                desiredNodePoolAutoscaling=autoscaling)
        elif options.locations:
            update = self.messages.ClusterUpdate(
                desiredLocations=options.locations)
        elif options.enable_master_authorized_networks is not None:
            # For update, we can either enable or disable.
            authorized_networks = self.messages.MasterAuthorizedNetworks(
                enabled=options.enable_master_authorized_networks)
            if options.master_authorized_networks:
                for network in options.master_authorized_networks:
                    authorized_networks.cidrs.append(
                        self.messages.CIDR(network=network))
            update = self.messages.ClusterUpdate(
                desiredMasterAuthorizedNetworks=authorized_networks)

        if (options.master_authorized_networks
                and not options.enable_master_authorized_networks):
            # Raise error if use --master-authorized-networks without
            # --enable-master-authorized-networks.
            raise util.Error(MISMATCH_AUTHORIZED_NETWORKS_ERROR_MSG)

        op = self.client.projects_zones_clusters.Update(
            self.messages.ContainerProjectsZonesClustersUpdateRequest(
                clusterId=cluster_ref.clusterId,
                zone=cluster_ref.zone,
                projectId=cluster_ref.projectId,
                updateClusterRequest=self.messages.UpdateClusterRequest(
                    update=update)))
        return self.ParseOperation(op.name)
Exemplo n.º 18
0
def ValidateBasicAuthFlags(args):
  """Validates flags associated with basic auth.

  Check that args don't conflict, but only if they're both specified; overwrites
  username if enable_basic_auth is specified; and checks that password is set
  only if username is non-empty.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Raises:
    util.Error, if flags conflict.
  """
  if args.IsSpecified('enable_basic_auth'):
    if args.IsSpecified('username'):
      raise util.Error(constants.USERNAME_ENABLE_BASIC_AUTH_ERROR_MSG)
    if not args.enable_basic_auth:
      args.username = ''
    # Right now, enable_basic_auth is a no-op because username defaults to
    # admin.
  if not args.username and args.IsSpecified('password'):
    raise util.Error(constants.USERNAME_PASSWORD_ERROR_MSG)
 def FindNodePool(self, cluster, pool_name=None):
     """Find the node pool with the given name in the cluster."""
     msg = ''
     if pool_name:
         for np in cluster.nodePools:
             if np.name == pool_name:
                 return np
         msg = NO_SUCH_NODE_POOL_ERROR_MSG.format(cluster=cluster.name,
                                                  name=pool_name) + linesep
     elif len(cluster.nodePools) == 1:
         return cluster.nodePools[0]
     # Couldn't find a node pool with that name or a node pool was not specified.
     msg += NO_NODE_POOL_SELECTED_ERROR_MSG + linesep.join(
         [np.name for np in cluster.nodePools])
     raise util.Error(msg)
Exemplo n.º 20
0
def _GetGKEKubeconfig(location_id, cluster_id, temp_kubeconfig_dir):
    """The kubeconfig of GKE Cluster is fetched using the GKE APIs.

  The 'KUBECONFIG' value in `os.environ` will be temporarily updated with
  the temporary kubeconfig's path if the kubeconfig arg is not None.
  Consequently, subprocesses started with
  googlecloudsdk.core.execution_utils.Exec will see the temporary KUBECONFIG
  environment variable.

  Using GKE APIs the GKE cluster is validated, and the ClusterConfig object, is
  persisted in the temporarily updated 'KUBECONFIG'.

  Args:
    location_id: string, the id of the location to which the cluster belongs
    cluster_id: string, the id of the cluster
    temp_kubeconfig_dir: TemporaryDirectory object

  Raises:
    Error: If unable to get credentials for kubernetes cluster.

  Returns:
    the path to the kubeconfig file
  """
    kubeconfig = os.path.join(temp_kubeconfig_dir.path, 'kubeconfig')
    old_kubeconfig = encoding.GetEncodedValue(os.environ, 'KUBECONFIG')
    try:
        encoding.SetEncodedValue(os.environ, 'KUBECONFIG', kubeconfig)
        gke_api = gke_api_adapter.NewAPIAdapter('v1')
        cluster_ref = gke_api.ParseCluster(cluster_id, location_id)
        cluster = gke_api.GetCluster(cluster_ref)
        auth = cluster.masterAuth
        valid_creds = auth and auth.clientCertificate and auth.clientKey
        # c_util.ClusterConfig.UseGCPAuthProvider() checks for
        # container/use_client_certificate setting
        if not valid_creds and not c_util.ClusterConfig.UseGCPAuthProvider():
            raise c_util.Error(
                'Unable to get cluster credentials. User must have edit '
                'permission on {}'.format(cluster_ref.projectId))
        c_util.ClusterConfig.Persist(cluster, cluster_ref.projectId)
    finally:
        if old_kubeconfig:
            encoding.SetEncodedValue(os.environ, 'KUBECONFIG', old_kubeconfig)
        else:
            del os.environ['KUBECONFIG']
    return kubeconfig
Exemplo n.º 21
0
def ParseCreateNodePoolOptionsBase(args):
    """Parses the flags provided with the node pool creation command."""
    if (args.IsSpecified('enable_cloud_endpoints')
            and properties.VALUES.container.new_scopes_behavior.GetBool()):
        raise util.Error(
            'Flag --[no-]enable-cloud-endpoints is not allowed if '
            'property container/ new_scopes_behavior is set to true.')
    if args.IsSpecified('enable_autorepair'):
        enable_autorepair = args.enable_autorepair
    else:
        # Node pools using COS support auto repairs, enable it for them by default.
        # Other node pools using (Ubuntu, custom images) don't support node auto
        # repairs, attempting to enable autorepair for them will result in API call
        # failing so don't do it.
        enable_autorepair = ((args.image_type or '').lower() in ['', 'cos'])
    flags.WarnForNodeModification(args, enable_autorepair)
    metadata = metadata_utils.ConstructMetadataDict(args.metadata,
                                                    args.metadata_from_file)
    return api_adapter.CreateNodePoolOptions(
        accelerators=args.accelerator,
        machine_type=args.machine_type,
        disk_size_gb=utils.BytesToGb(args.disk_size),
        scopes=args.scopes,
        node_version=args.node_version,
        enable_cloud_endpoints=args.enable_cloud_endpoints,
        num_nodes=args.num_nodes,
        local_ssd_count=args.local_ssd_count,
        tags=args.tags,
        node_labels=args.node_labels,
        node_taints=args.node_taints,
        enable_autoscaling=args.enable_autoscaling,
        max_nodes=args.max_nodes,
        min_cpu_platform=args.min_cpu_platform,
        min_nodes=args.min_nodes,
        image_type=args.image_type,
        image=args.image,
        image_project=args.image_project,
        image_family=args.image_family,
        preemptible=args.preemptible,
        enable_autorepair=enable_autorepair,
        enable_autoupgrade=args.enable_autoupgrade,
        service_account=args.service_account,
        disk_type=args.disk_type,
        metadata=metadata,
        max_pods_per_node=args.max_pods_per_node)
Exemplo n.º 22
0
def ValidateBasicAuthFlags(args):
  """Validates flags associated with basic auth.

  Overwrites username if enable_basic_auth is specified; checks that password is
  set if username is non-empty.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Raises:
    util.Error, if username is non-empty and password is not set.
  """
  if args.IsSpecified('enable_basic_auth'):
    if not args.enable_basic_auth:
      args.username = ''
    # Right now, enable_basic_auth is a no-op because username defaults to
    # admin.
  if not args.username and args.IsSpecified('password'):
    raise util.Error(constants.USERNAME_PASSWORD_ERROR_MSG)
Exemplo n.º 23
0
  def CreateCluster(self, cluster_ref, options):
    node_config = self.messages.NodeConfig()
    if options.node_machine_type:
      node_config.machineType = options.node_machine_type
    # TODO(user): support disk size via flag
    if options.node_disk_size_gb:
      node_config.diskSizeGb = options.node_disk_size_gb
    if options.node_source_image:
      raise util.Error('cannot specify node source image in container v1 api')
    scope_uris = ExpandScopeURIs(options.scopes)
    if options.enable_cloud_endpoints:
      scope_uris += _ENDPOINTS_SCOPES
    node_config.oauthScopes = sorted(set(scope_uris + _REQUIRED_SCOPES))

    cluster = self.messages.Cluster(
        name=cluster_ref.clusterId,
        initialNodeCount=options.num_nodes,
        nodeConfig=node_config,
        masterAuth=self.messages.MasterAuth(username=options.user,
                                            password=options.password))
    if options.cluster_version:
      cluster.initialClusterVersion = options.cluster_version
    if options.network:
      cluster.network = options.network
    if options.cluster_ipv4_cidr:
      cluster.clusterIpv4Cidr = options.cluster_ipv4_cidr
    if not options.enable_cloud_logging:
      cluster.loggingService = 'none'
    if not options.enable_cloud_monitoring:
      cluster.monitoringService = 'none'
    if options.subnetwork:
      cluster.subnetwork = options.subnetwork

    create_cluster_req = self.messages.CreateClusterRequest(cluster=cluster)

    req = self.messages.ContainerProjectsZonesClustersCreateRequest(
        createClusterRequest=create_cluster_req,
        projectId=cluster_ref.projectId,
        zone=cluster_ref.zone)
    operation = self.client.projects_zones_clusters.Create(req)
    return self.ParseOperation(operation.name)
Exemplo n.º 24
0
def _BaseRun(args, context):
  """Base operations for `get-credentials` run command."""
  util.CheckKubectlInstalled()
  adapter = context['api_adapter']
  location_get = context['location_get']
  location = location_get(args)
  cluster_ref = adapter.ParseCluster(args.name, location)
  log.status.Print('Fetching cluster endpoint and auth data.')
  # Call DescribeCluster to get auth info and cache for next time
  cluster = adapter.GetCluster(cluster_ref)
  auth = cluster.masterAuth
  # TODO(b/70856999) Make this consistent with the checks in
  # api_lib/container/kubeconfig.py.
  missing_creds = not (auth and auth.clientCertificate and auth.clientKey)
  if missing_creds and not util.ClusterConfig.UseGCPAuthProvider():
    raise util.Error('get-credentials requires edit permission on {0}'.format(
        cluster_ref.projectId))
  if not adapter.IsRunning(cluster):
    log.warning(NOT_RUNNING_MSG.format(cluster_ref.clusterId))

  return cluster, cluster_ref
Exemplo n.º 25
0
def ValidateBasicAuthFlags(args):
    """Validates flags associated with basic auth.

  Overwrites username if enable_basic_auth is specified; checks that password is
  set if username is non-empty.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Raises:
    util.Error, if username is non-empty and password is not set.
  """
    if args.IsSpecified('enable_basic_auth'):
        if not args.enable_basic_auth:
            args.username = ''
        # `enable_basic_auth == true` is a no-op defaults are resoved server-side
        # based on the version of the cluster. For versions before 1.12, this is
        # 'admin', otherwise '' (disabled).
    if not args.username and args.IsSpecified('password'):
        raise util.Error(constants.USERNAME_PASSWORD_ERROR_MSG)
Exemplo n.º 26
0
def MungeBasicAuthFlags(args):
  """Munges flags associated with basic auth.

  If --enable-basic-auth is specified, converts it --username value, and checks
  that --password is only specified if it makes sense.

  Args:
    args: an argparse namespace. All the arguments that were provided to this
      command invocation.

  Raises:
    util.Error, if flags conflict.
  """
  if args.IsSpecified('enable_basic_auth'):
    if not args.enable_basic_auth:
      args.username = ''
    else:
      # Even though this is the default for `clusters create`, we still need to
      # set it for `clusters update`.
      args.username = '******'
  if not args.username and args.IsSpecified('password'):
    raise util.Error(constants.USERNAME_PASSWORD_ERROR_MSG)
Exemplo n.º 27
0
def ParseCreateNodePoolOptionsBase(args):
    """Parses the flags provided with the node pool creation command."""
    if (args.IsSpecified('enable_cloud_endpoints')
            and properties.VALUES.container.new_scopes_behavior.GetBool()):
        raise util.Error(
            'Flag --[no-]enable-cloud-endpoints is not allowed if '
            'property container/ new_scopes_behavior is set to true.')
    enable_autorepair = cmd_util.GetAutoRepair(args)
    flags.WarnForNodeModification(args, enable_autorepair)
    metadata = metadata_utils.ConstructMetadataDict(args.metadata,
                                                    args.metadata_from_file)
    return api_adapter.CreateNodePoolOptions(
        accelerators=args.accelerator,
        machine_type=args.machine_type,
        disk_size_gb=utils.BytesToGb(args.disk_size),
        scopes=args.scopes,
        node_version=args.node_version,
        enable_cloud_endpoints=args.enable_cloud_endpoints,
        num_nodes=args.num_nodes,
        local_ssd_count=args.local_ssd_count,
        tags=args.tags,
        node_labels=args.node_labels,
        node_taints=args.node_taints,
        enable_autoscaling=args.enable_autoscaling,
        max_nodes=args.max_nodes,
        min_cpu_platform=args.min_cpu_platform,
        min_nodes=args.min_nodes,
        image_type=args.image_type,
        image=args.image,
        image_project=args.image_project,
        image_family=args.image_family,
        preemptible=args.preemptible,
        enable_autorepair=enable_autorepair,
        enable_autoupgrade=cmd_util.GetAutoUpgrade(args),
        service_account=args.service_account,
        disk_type=args.disk_type,
        metadata=metadata,
        max_pods_per_node=args.max_pods_per_node)
Exemplo n.º 28
0
def DeployConnectAgent(response, args):
    """Python hook to deploy connect agent.

  Args:
    response: response to be returned.
    args: arguments of the command.

  Returns:
    modified response
  """
    if args.agent_deployed:
        return response

    # project = properties.VALUES.core.project.GetOrFail()
    # Exit if kubectl is not installed.
    if not c_util.CheckKubectlInstalled():
        log.warning(
            'kubectl not installed, could not install the connect agent. ')
        return

    image = args.docker_image
    if not image:
        # Get the SHA for the default image.
        try:
            digest = ImageDigestForContainerImage(DEFAULT_CONNECT_AGENT_IMAGE,
                                                  DEFAULT_CONNECT_AGENT_TAG)
            image = '{}@{}'.format(DEFAULT_CONNECT_AGENT_IMAGE, digest)
        except Exception as exp:
            raise c_util.Error(
                'could not determine image digest for {}:{}: {}'.format(
                    DEFAULT_CONNECT_AGENT_IMAGE, DEFAULT_CONNECT_AGENT_TAG,
                    exp))

    log.status.Print('The agent image that would be used is {}'.format(image))

    # TODO(b/123907152): implement the manifest after Docker image is ready.

    return response
Exemplo n.º 29
0
    def Run(self, args):
        """This is what gets called when the user runs this command.

    Args:
      args: an argparse namespace. All the arguments that were provided to this
        command invocation.

    Returns:
      Some value that we want to have printed later.
    """
        adapter = self.context['api_adapter']
        location_get = self.context['location_get']
        location = location_get(args)
        if getattr(args, 'region', None):
            message = messages.NonGAFeatureUsingV1APIWarning(
                self._release_track)
            if message:
                console_io.PromptContinue(message=message, cancel_on_no=True)
        cluster_refs = []
        for name in args.names:
            cluster_refs.append(adapter.ParseCluster(name, location))
        console_io.PromptContinue(message=util.ConstructList(
            'The following clusters will be deleted.', [
                '[{name}] in [{zone}]'.format(name=ref.clusterId,
                                              zone=adapter.Zone(ref))
                for ref in cluster_refs
            ]),
                                  throw_if_unattended=True,
                                  cancel_on_no=True)

        operations = []
        errors = []
        # Issue all deletes first
        for cluster_ref in cluster_refs:
            try:
                # Make sure it exists (will raise appropriate error if not)
                adapter.GetCluster(cluster_ref)

                op_ref = adapter.DeleteCluster(cluster_ref)
                operations.append((op_ref, cluster_ref))
            except apitools_exceptions.HttpError as error:
                errors.append(
                    str(exceptions.HttpException(error,
                                                 util.HTTP_ERROR_FORMAT)))
            except util.Error as error:
                errors.append(error)
        if not args. async:
            # Poll each operation for completion
            for operation_ref, cluster_ref in operations:
                try:
                    adapter.WaitForOperation(operation_ref,
                                             'Deleting cluster {0}'.format(
                                                 cluster_ref.clusterId),
                                             timeout_s=args.timeout)
                    # Purge cached config files
                    util.ClusterConfig.Purge(cluster_ref.clusterId,
                                             adapter.Zone(cluster_ref),
                                             cluster_ref.projectId)
                    if properties.VALUES.container.cluster.Get(
                    ) == cluster_ref.clusterId:
                        properties.PersistProperty(
                            properties.VALUES.container.cluster, None)
                    log.DeletedResource(cluster_ref)
                except apitools_exceptions.HttpError as error:
                    errors.append(
                        exceptions.HttpException(error,
                                                 util.HTTP_ERROR_FORMAT))
                except util.Error as error:
                    errors.append(error)

        if errors:
            raise util.Error(
                util.ConstructList('Some requests did not succeed:', errors))
    def CreateCluster(self, cluster_ref, options):
        node_config = self.messages.NodeConfig()
        if options.node_machine_type:
            node_config.machineType = options.node_machine_type
        if options.node_disk_size_gb:
            node_config.diskSizeGb = options.node_disk_size_gb
        if options.node_source_image:
            raise util.Error(
                'cannot specify node source image in container v1 api')
        scope_uris = ExpandScopeURIs(options.scopes)
        if options.enable_cloud_endpoints:
            scope_uris += _ENDPOINTS_SCOPES
        node_config.oauthScopes = sorted(set(scope_uris + _REQUIRED_SCOPES))

        if options.local_ssd_count:
            node_config.localSsdCount = options.local_ssd_count

        if options.tags:
            node_config.tags = options.tags
        else:
            node_config.tags = []

        if options.image_type:
            node_config.imageType = options.image_type

        _AddNodeLabelsToNodeConfig(node_config, options)

        max_nodes_per_pool = options.max_nodes_per_pool or MAX_NODES_PER_POOL
        pools = (options.num_nodes + max_nodes_per_pool -
                 1) / max_nodes_per_pool
        if pools == 1:
            pool_names = ['default-pool'
                          ]  # pool consistency with server default
        else:
            # default-pool-0, -1, ...
            pool_names = [
                'default-pool-{0}'.format(i) for i in range(0, pools)
            ]

        pools = []
        per_pool = (options.num_nodes + len(pool_names) - 1) / len(pool_names)
        to_add = options.num_nodes
        for name in pool_names:
            nodes = per_pool if (to_add > per_pool) else to_add
            autoscaling = None
            if options.enable_autoscaling:
                autoscaling = self.messages.NodePoolAutoscaling(
                    enabled=options.enable_autoscaling,
                    minNodeCount=options.min_nodes,
                    maxNodeCount=options.max_nodes)
            pools.append(
                self.messages.NodePool(name=name,
                                       initialNodeCount=nodes,
                                       config=node_config,
                                       autoscaling=autoscaling))
            to_add -= nodes

        cluster = self.messages.Cluster(name=cluster_ref.clusterId,
                                        nodePools=pools,
                                        masterAuth=self.messages.MasterAuth(
                                            username=options.user,
                                            password=options.password))
        if options.additional_zones:
            cluster.locations = sorted([cluster_ref.zone] +
                                       options.additional_zones)
        if options.cluster_version:
            cluster.initialClusterVersion = options.cluster_version
        if options.network:
            cluster.network = options.network
        if options.cluster_ipv4_cidr:
            cluster.clusterIpv4Cidr = options.cluster_ipv4_cidr
        if not options.enable_cloud_logging:
            cluster.loggingService = 'none'
        if not options.enable_cloud_monitoring:
            cluster.monitoringService = 'none'
        if options.subnetwork:
            cluster.subnetwork = options.subnetwork
        if options.disable_addons:
            addons = self._AddonsConfig(
                disable_ingress=INGRESS in options.disable_addons or None,
                disable_hpa=HPA in options.disable_addons or None)
            cluster.addonsConfig = addons

        if options.enable_kubernetes_alpha:
            cluster.enableKubernetesAlpha = options.enable_kubernetes_alpha

        create_cluster_req = self.messages.CreateClusterRequest(
            cluster=cluster)

        req = self.messages.ContainerProjectsZonesClustersCreateRequest(
            createClusterRequest=create_cluster_req,
            projectId=cluster_ref.projectId,
            zone=cluster_ref.zone)
        operation = self.client.projects_zones_clusters.Create(req)
        return self.ParseOperation(operation.name)