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:
      (output, error), where
        output: str, raw output of the kubectl command.
        error: subprocess.CalledProcessError, if the command exited with
          non-zero status, None if command exited with success.

    Raises:
      util.Error: if the current platform is not supported by kubectl.
    """
    local = platforms.Platform.Current()
    if local.operating_system == platforms.OperatingSystem.WINDOWS:
      raise util.Error(
          'This command requires the kubernetes client (kubectl), which is '
          'not available for Windows at this time.')
    if not WhichKubectl():
      raise util.Error(
          'This command requires the kubernetes client (kubectl), which is '
          'installed with the default gcloud components. Run '
          '\'gcloud components update\', or make sure kubectl is '
          'installed somewhere on your path.')

    cluster_config = self.LoadClusterConfig(args)
    # Print deprecation warning, including command to switch context, if needed
    kubeconfig = kconfig.Kubeconfig.Default()
    use_context = ''
    if kubeconfig.current_context != cluster_config.kube_context:
      use_context = '\nkubectl config use-context '+cluster_config.kube_context
    log.warn(DEPRECATION_WARNING.format(
        use_context=use_context, args=' '.join(args.kubectl_args)))

    output, error = self.CallKubectl(cluster_config, args.kubectl_args)
    # If error looks like stale config, try refetching cluster config
    if error and (KUBECTL_TLS_ERR in output or
                  KUBECTL_TIMEOUT_ERR in output):
      log.warn(
          'Command failed with error: %s. Purging config cache and retrying'
          % error.output)
      args.purge_config_cache = True
      cluster_config = self.LoadClusterConfig(args)
      output, error = self.CallKubectl(cluster_config, args.kubectl_args)
    return output, error
  def LoadClusterConfig(self, args):
    """Load and return ClusterConfig prior to calling a kubectl command.

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

    Returns:
      ClusterConfig for the project,zone,cluster specified by args/properties.

    Raises:
      util.Error: if container API reports cluster is not running.
    """
    name = properties.VALUES.container.cluster.Get(required=True)
    cluster_ref = util.ParseCluster(name, self.context)

    c_config = util.ClusterConfig.Load(
        cluster_ref.clusterId, cluster_ref.zoneId, cluster_ref.projectId)
    if args.purge_config_cache:
      util.ClusterConfig.Purge(
          cluster_ref.clusterId, cluster_ref.zoneId, cluster_ref.projectId)
      c_config = None

    if not c_config or not c_config.has_certs:
      log.status.Print('Fetching cluster endpoint and auth data.')
      # Call DescribeCluster to get auth info and cache for next time
      cluster = util.DescribeCluster(cluster_ref, self.context)
      messages = self.context['container_messages']
      if cluster.status != messages.Cluster.StatusValueValuesEnum.running:
        raise util.Error('cluster %s is not running' % cluster_ref.clusterId)
      c_config = util.ClusterConfig.Persist(
          cluster, cluster_ref.projectId, self.cli)
    return c_config
Exemple #3
0
def ExpandScopeURIs(scopes):
    """Expand scope names to the fully qualified uris.

  Args:
    scopes: [str,] list of scope names. Can be short names ('compute-rw')
      or full urls ('https://www.googleapis.com/auth/compute')

  Returns:
    list of str, full urls for recognized scopes.

  Raises:
    util.Error, if any scope provided is not recognized. See SCOPES in
        cloud/sdk/compute/lib/constants.py.
  """

    scope_uris = []
    for scope in scopes:
        # Expand any scope aliases (like 'storage-rw') that the user provided
        # to their official URL representation.
        expanded = constants.SCOPES.get(scope, None)
        if not expanded:
            if scope in constants.SCOPES.values():
                expanded = scope
            else:
                raise util.Error(
                    '[{0}] is an illegal value for [--scopes].'.format(scope))
        scope_uris.append(expanded)
    return scope_uris
Exemple #4
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
Exemple #5
0
    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.
    """
        with console_io.ProgressTracker(message, autotick=True):
            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
                except apitools_base.HttpError as error:
                    log.debug('GetOperation failed: %s', error)
                    # Keep trying until we timeout in case error is transient.
                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
Exemple #6
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_base.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_base.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))
Exemple #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: Always. Command is moved/deprecated.
    """
        raise util.Error("""\
This command has been moved. Please run

  $ {cmd_path} clusters get-credentials""".format(
            cmd_path=' '.join(args.command_path[:-1])))
  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.
    """
    name = properties.VALUES.container.cluster.Get(required=True)
    adapter = self.context['api_adapter']
    cluster_ref = adapter.ParseCluster(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)
    if not adapter.IsRunning(cluster):
      raise util.Error('cluster %s is not running' % cluster_ref.clusterId)
    util.ClusterConfig.Persist(cluster, cluster_ref.projectId, self.cli)
Exemple #9
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)
        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'

        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)
Exemple #10
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.
    """
    name = properties.VALUES.container.cluster.Get(required=True)
    cluster_ref = util.ParseCluster(name, self.context)

    log.status.Print('Fetching cluster endpoint and auth data.')
    # Call DescribeCluster to get auth info and cache for next time
    cluster = util.DescribeCluster(cluster_ref, self.context)
    messages = self.context['container_messages']
    if cluster.status != messages.Cluster.StatusValueValuesEnum.running:
      raise util.Error('cluster %s is not running' % cluster_ref.clusterId)
    c_config = util.ClusterConfig.Persist(
        cluster, cluster_ref.projectId, self.cli)
    kubeconfig = kconfig.Kubeconfig.Default()
    kubeconfig.SetCurrentContext(c_config.kube_context)
    kubeconfig.SaveToFile()
Exemple #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.

    Returns:
      Some value that we want to have printed later.
    """
    adapter = self.context['api_adapter']

    cluster_refs = []
    for name in args.names:
      cluster_refs.append(adapter.ParseCluster(name))

    if not 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):
      raise util.Error('Deletion aborted by user.')

    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_base.HttpError as error:
        errors.append(util.GetError(error))
      except util.Error as error:
        errors.append(error)
    if args.wait:
      # 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_base.HttpError as error:
          errors.append(util.GetError(error))
        except util.Error as error:
          errors.append(error)

    if errors:
      raise util.Error(util.ConstructList(
          'Some requests did not succeed:', errors))