Beispiel #1
0
    def Run(self, args):
        """Run 'service-management deploy'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the Update API call.

    Raises:
      SwaggerUploadException: if the provided service configuration file is
          rejected by the Service Management API.

      BadFileExceptionn: if the provided service configuration file is invalid
          or cannot be read.
    """
        with open(args.service_config_file, 'r') as f:
            config_contents = f.read()

        # Try to load the file as JSON. If that fails, try YAML.
        service_config_dict = services_util.LoadJsonOrYaml(config_contents)
        if not service_config_dict:
            raise calliope_exceptions.BadFileException(
                'Could not read JSON or YAML from service config file %s.' %
                args.service_config_file)

        # Check to see if the Endpoints meta service needs to be enabled.
        enable_api.EnableServiceIfDisabled(
            self.project, services_util.GetEndpointsServiceName(), args. async)

        # Get the service name out of the service configuration
        if 'swagger' in service_config_dict:
            self.service_name = service_config_dict.get('host', None)
            # Check if we need to create the service.
            services_util.CreateServiceIfNew(self.service_name, self.project)
            # Push the service configuration.
            self.service_version = services_util.PushOpenApiServiceConfig(
                self.service_name, config_contents,
                os.path.basename(args.service_config_file), args. async)
        else:
            self.service_name = service_config_dict.get('name', None)
            # Check if we need to create the service.
            services_util.CreateServiceIfNew(self.service_name, self.project)
            # Push the service configuration.
            self.service_version = services_util.PushGoogleServiceConfig(
                self.service_name, self.project, config_contents)

        if not self.service_version:
            raise calliope_exceptions.ToolException(
                'Failed to retrieve Service Configuration Version')

        # Create a Rollout for the new service configuration
        percentages = (
            self.services_messages.TrafficPercentStrategy.PercentagesValue())
        percentages.additionalProperties.append(
            (self.services_messages.TrafficPercentStrategy.PercentagesValue.
             AdditionalProperty(key=self.service_version, value=100.0)))
        traffic_percent_strategy = (
            self.services_messages.TrafficPercentStrategy(
                percentages=percentages))
        rollout = self.services_messages.Rollout(
            serviceName=self.service_name,
            trafficPercentStrategy=traffic_percent_strategy,
        )
        rollout_operation = self.services_client.services_rollouts.Create(
            rollout)
        services_util.ProcessOperationResult(rollout_operation, args. async)

        # Check to see if the service is already enabled
        enable_api.EnableServiceIfDisabled(self.project, self.service_name,
                                           args. async)
Beispiel #2
0
    def Run(self, args):
        """Run 'service-management deploy'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the Update API call.

    Raises:
      BadFileExceptionn: if the provided service configuration files are
          invalid or cannot be read.
    """
        messages = services_util.GetMessagesModule()
        client = services_util.GetClientInstance()

        file_types = messages.ConfigFile.FileTypeValueValuesEnum
        self.service_name = self.service_version = config_contents = None
        config_files = []

        self.validate_only = args.validate_only

        # If we're not doing a validate-only run, we don't want to output the
        # resource directly unless the user specifically requests it using the
        # --format flag. The Epilog will show useful information after deployment
        # is complete.
        if not self.validate_only and not args.IsSpecified('format'):
            args.format = 'none'

        for service_config_file in args.service_config_file:
            config_contents = services_util.ReadServiceConfigFile(
                service_config_file)

            if services_util.FilenameMatchesExtension(
                    service_config_file, ['.json', '.yaml', '.yml']):
                # Try to load the file as JSON. If that fails, try YAML.
                service_config_dict = services_util.LoadJsonOrYaml(
                    config_contents)
                if not service_config_dict:
                    raise calliope_exceptions.BadFileException(
                        'Could not read JSON or YAML from service config file '
                        '[{0}].'.format(service_config_file))

                if 'swagger' in service_config_dict:
                    if 'host' not in service_config_dict:
                        raise calliope_exceptions.BadFileException((
                            'Malformed input. Found Swagger service config in file [{}], '
                            'but no host was specified. Add a host specification to the '
                            'config file.').format(service_config_file))
                    if not self.service_name and service_config_dict.get(
                            'host'):
                        self.service_name = service_config_dict.get('host')

                    # Always use YAML for Open API because JSON is a subset of YAML.
                    config_files.append(
                        self.MakeConfigFileMessage(config_contents,
                                                   service_config_file,
                                                   file_types.OPEN_API_YAML))
                elif service_config_dict.get('type') == 'google.api.Service':
                    if not self.service_name and service_config_dict.get(
                            'name'):
                        self.service_name = service_config_dict.get('name')

                    config_files.append(
                        self.MakeConfigFileMessage(
                            config_contents, service_config_file,
                            file_types.SERVICE_CONFIG_YAML))
                elif 'name' in service_config_dict:
                    # This is a special case. If we have been provided a Google Service
                    # Configuration file which has a service 'name' field, but no 'type'
                    # field, we have to assume that this is a normalized service config,
                    # and can be uploaded via the CreateServiceConfig API. Therefore,
                    # we can short circute the process here.
                    if len(args.service_config_file) > 1:
                        raise calliope_exceptions.BadFileException((
                            'Ambiguous input. Found normalized service configuration in '
                            'file [{0}], but received multiple input files. To upload '
                            'normalized service config, please provide it separately from '
                            'other input files to avoid ambiguity.'
                        ).format(service_config_file))

                    # If this is a validate-only run, abort now, since this is not
                    # supported in the ServiceConfigs.Create API
                    if self.validate_only:
                        raise exceptions.InvalidFlagError(
                            'The --validate-only flag is not supported when using '
                            'normalized service configs as input.')

                    self.service_name = service_config_dict.get('name')
                    config_files = []
                    break
                else:
                    raise calliope_exceptions.BadFileException((
                        'Unable to parse Open API, or Google Service Configuration '
                        'specification from {0}').format(service_config_file))

            elif services_util.IsProtoDescriptor(service_config_file):
                config_files.append(
                    self.MakeConfigFileMessage(
                        config_contents, service_config_file,
                        file_types.FILE_DESCRIPTOR_SET_PROTO))
            else:
                raise calliope_exceptions.BadFileException((
                    'Could not determine the content type of file [{0}]. Supported '
                    'extensions are .json .yaml .yml .pb. and .descriptor'
                ).format(service_config_file))

        # Check to see if the Endpoints meta service needs to be enabled.
        enable_api.EnableServiceIfDisabled(
            properties.VALUES.core.project.Get(required=True),
            services_util.GetEndpointsServiceName(), args. async)
        # Check if we need to create the service.
        services_util.CreateServiceIfNew(
            self.service_name,
            properties.VALUES.core.project.Get(required=True))

        if config_files:
            push_config_result = services_util.PushMultipleServiceConfigFiles(
                self.service_name,
                config_files,
                args. async,
                validate_only=self.validate_only)
            self.service_config_id = (
                services_util.GetServiceConfigIdFromSubmitConfigSourceResponse(
                    push_config_result))
        else:
            push_config_result = services_util.PushNormalizedGoogleServiceConfig(
                self.service_name,
                properties.VALUES.core.project.Get(required=True),
                config_contents)
            self.service_config_id = push_config_result.id

        if not self.service_config_id:
            raise exceptions.InvalidConditionError(
                'Failed to retrieve Service Configuration Id.')

        # Run the Push Advisor to see if we need to warn the user of any
        # potentially hazardous changes to the service configuration.
        if self.CheckPushAdvisor(args.force):
            return None

        # Create a Rollout for the new service configuration
        if not self.validate_only:
            percentages = messages.TrafficPercentStrategy.PercentagesValue()
            percentages.additionalProperties.append(
                (messages.TrafficPercentStrategy.PercentagesValue.
                 AdditionalProperty(key=self.service_config_id, value=100.0)))
            traffic_percent_strategy = messages.TrafficPercentStrategy(
                percentages=percentages)
            rollout = messages.Rollout(
                serviceName=self.service_name,
                trafficPercentStrategy=traffic_percent_strategy,
            )
            rollout_operation = client.services_rollouts.Create(rollout)
            services_util.ProcessOperationResult(rollout_operation,
                                                 args. async)

            # Check to see if the service is already enabled
            enable_api.EnableServiceIfDisabled(
                properties.VALUES.core.project.Get(required=True),
                self.service_name, args. async)

        return push_config_result
Beispiel #3
0
    def Run(self, args):
        """Run 'service-management deploy'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the Update API call.

    Raises:
      HttpException: An http error response was received while executing api
          request.
    """
        with open(args.service_config_file, 'r') as f:
            config_contents = f.read()

        # Try to load the file as JSON. If that fails, try YAML.
        service_config_dict = services_util.LoadJsonOrYaml(config_contents)
        if not service_config_dict:
            raise exceptions.BadFileException(
                'Could not read JSON or YAML from service config file %s.' %
                args.service_config_file)

        # Check if the provided file is a swagger spec that needs to be converted
        # to Google Service Configuration
        if 'swagger' in service_config_dict:
            swagger_file = self.services_messages.File(
                contents=config_contents,
                path=os.path.basename(args.service_config_file))
            # TODO(user): Add support for swagger file references later
            # This requires the API to support multiple files first. b/23353397
            swagger_spec = self.services_messages.SwaggerSpec(
                swaggerFiles=[swagger_file])
            request = self.services_messages.ConvertConfigRequest(
                swaggerSpec=swagger_spec, )

            try:
                response = self.services_client.v1.ConvertConfig(request)
            except apitools_exceptions.HttpError as error:
                raise exceptions.HttpException(services_util.GetError(error))

            diagnostics = response.diagnostics
            if diagnostics:
                kind = self.services_messages.Diagnostic.KindValueValuesEnum
                for diagnostic in diagnostics:
                    logger = log.error if diagnostic.kind == kind.ERROR else log.warning
                    logger('{l}: {m}'.format(l=diagnostic.location,
                                             m=diagnostic.message))

            service_config = response.serviceConfig
        else:
            # If not Swagger, assume that we are dealing with Google Service Config
            service_config = encoding.JsonToMessage(
                self.services_messages.Service, config_contents)

        managed_service = self.services_messages.ManagedService(
            serviceConfig=service_config, serviceName=service_config.name)

        # Set the serviceConfig producerProjectId if it is not already set
        if not managed_service.serviceConfig.producerProjectId:
            managed_service.serviceConfig.producerProjectId = self.project

        request = self.services_messages.ServicemanagementServicesUpdateRequest(
            serviceName=managed_service.serviceName,
            managedService=managed_service,
        )

        try:
            result = self.services_client.services.Update(request)
        except apitools_exceptions.HttpError as error:
            raise exceptions.HttpException(services_util.GetError(error))

        # Validate the response type to avoid surprise errors below
        services_util.RaiseIfResultNotTypeOf(result,
                                             self.services_messages.Operation)

        service_name = None
        config_id = None
        # Fish the serviceName and serviceConfig.id fields from the proto Any
        # that is returned in result.response
        for prop in result.response.additionalProperties:
            if prop.key == 'serviceName':
                service_name = prop.value.string_value
            elif prop.key == 'serviceConfig':
                for item in prop.value.object_value.properties:
                    if item.key == 'id':
                        config_id = item.value.string_value
                        break

        if service_name and config_id:
            log.status.Print(
                ('\nService Configuration with version "{0}" uploaded '
                 'for service "{1}"\n').format(config_id, service_name))
        else:
            log.error('Failed to retrieve Service Name and '
                      'Service Configuration Version')

        # Remove the response portion of the resulting operation since
        # it can be extremely large.
        result.response = None

        return services_util.ProcessOperationResult(result, args. async)
Beispiel #4
0
def PushServiceConfig(swagger_file, project, client, messages):
    """Pushes Service Configuration to Google Service Management.

  Args:
    swagger_file: full path to a JSON file containing the swagger spec.
    project: the Google cloud project Id
    client: the client to use for calls to Service Management API
    messages: the client library messages to use for Service Management API

  Raises:
    SwaggerOpenException: if input is malformed or file cannot be read
    SwaggerUploadException: if service fails to convert swagger, or
      upload of the service configuration conversion result fails
    ValueError: if the required inputs are not provided.

  Returns:
    Operation: a long running asynchronous Operation
  """
    if not swagger_file:
        raise ValueError(
            'Open API (Swagger) specification file path must be provided.')
    if not project:
        raise ValueError('Project Id must be provided.')
    if not client:
        raise ValueError('Service Management client must be provided.')
    if not messages:
        raise ValueError(
            'Service Management client messages must be provided.')

    swagger_file_contents = None
    try:
        with open(swagger_file) as f:
            swagger_file_contents = f.read()
    except IOError:
        raise SwaggerOpenException(
            'Unable to read swagger spec file "{0}"'.format(swagger_file))

    # Try to load the file as JSON or YAML.
    service_config_dict = services_util.LoadJsonOrYaml(swagger_file_contents)
    if not service_config_dict:
        raise SwaggerOpenException(
            'Could not read JSON or YAML from Open API (Swagger) file {}.'.
            format(swagger_file))

    # Check to see if the Endpoints meta service needs to be enabled.
    enable_api.EnableServiceIfDisabled(project,
                                       services_util.GetEndpointsServiceName(),
                                       async=False)

    # First, get the Open API specification contents, and convert it to
    # Google Service Config. This is only needed at the moment for the
    # Diagnostics information the ConvertConfig generates.
    # TODO(b/30276465): When the Diagnostics information is available via the
    # SubmitSourceConfig API, remove the usage of ConvertConfig API.
    swagger_file_obj = messages.File(contents=swagger_file_contents,
                                     path=swagger_file)
    swagger_spec = messages.SwaggerSpec(swaggerFiles=[swagger_file_obj])
    request = messages.ConvertConfigRequest(swaggerSpec=swagger_spec)
    try:
        response = client.v1.ConvertConfig(request)
    except apitools_base.exceptions.HttpError as error:
        raise SwaggerUploadException(_GetErrorMessage(error))

    if response.diagnostics:
        kind = messages.Diagnostic.KindValueValuesEnum
        for diagnostic in response.diagnostics:
            logger = log.error if diagnostic.kind == kind.ERROR else log.warning
            logger('{l}: {m}'.format(l=diagnostic.location,
                                     m=diagnostic.message))

    if not response.serviceConfig:
        raise SwaggerUploadException('Failed to upload service configuration.')

    # Create an endpoints directory under the location of the swagger config
    # which will contain the service.json file needed by ESP.
    # This file+directory will be carried to the App Engine Flexible VM via the
    # app container.
    # TODO(b/28090287): Remove this when ESP is able to pull this configuration
    # directly from Service Management API.
    swagger_path = os.path.dirname(swagger_file)
    service_json_file = os.path.join(swagger_path, 'endpoints', 'service.json')
    WriteServiceConfigToFile(
        service_json_file,
        apitools_base.encoding.MessageToJson(response.serviceConfig))

    service_name = service_config_dict.get('host', None)
    # Create the Service resource if it does not already exist.
    services_util.CreateServiceIfNew(service_name, project)

    # Push the service configuration.
    config_id = services_util.PushOpenApiServiceConfig(
        service_name,
        swagger_file_contents,
        os.path.basename(swagger_file),
        async=False)

    if config_id and service_name:
        # Print this to screen and to the log because the output is needed by the
        # human user.
        log.status.Print(
            ('\nService Configuration with version [{0}] uploaded '
             'for service [{1}]\n').format(config_id, service_name))
    else:
        raise SwaggerUploadException(
            'Failed to retrieve Service Configuration Version')

    # Create a Rollout for the new service configuration
    percentages = messages.TrafficPercentStrategy.PercentagesValue()
    percentages.additionalProperties.append(
        messages.TrafficPercentStrategy.PercentagesValue.AdditionalProperty(
            key=config_id, value=100.0))
    traffic_percent_strategy = messages.TrafficPercentStrategy(
        percentages=percentages)
    rollout = messages.Rollout(
        serviceName=service_name,
        trafficPercentStrategy=traffic_percent_strategy,
    )
    rollout_operation = client.services_rollouts.Create(rollout)
    services_util.ProcessOperationResult(rollout_operation, async=False)

    # Enable the service for the producer project if it is not already enabled
    enable_api.EnableServiceIfDisabled(project, service_name, async=False)
Beispiel #5
0
    def Run(self, args):
        """Run 'service-management deploy'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the Update API call.

    Raises:
      HttpException: An http error response was received while executing api
          request.
    """
        with open(args.service_config_file, 'r') as f:
            config_contents = f.read()

        # Try to load the file as JSON. If that fails, try YAML.
        service_config_dict = services_util.LoadJsonOrYaml(config_contents)
        if not service_config_dict:
            raise exceptions.BadFileException(
                'Could not read JSON or YAML from service config file %s.' %
                args.service_config_file)

        # Check if the provided file is a swagger spec that needs to be converted
        # to Google Service Configuration
        if 'swagger' in service_config_dict:
            swagger_file = self.services_messages.File(
                contents=config_contents, path=args.service_config_file)
            # TODO(user): Add support for swagger file references later
            # This requires the API to support multiple files first. b/23353397
            swagger_spec = self.services_messages.SwaggerSpec(
                swaggerFiles=[swagger_file])
            request = self.services_messages.ConvertConfigRequest(
                swaggerSpec=swagger_spec, )

            try:
                response = self.services_client.v1.ConvertConfig(request)
            except apitools_exceptions.HttpError as error:
                raise exceptions.HttpException(services_util.GetError(error))

            diagnostics = response.diagnostics
            if diagnostics:
                kind = self.services_messages.Diagnostic.KindValueValuesEnum
                for diagnostic in diagnostics:
                    logger = log.error if diagnostic.kind == kind.ERROR else log.warning
                    logger('{l}: {m}'.format(l=diagnostic.location,
                                             m=diagnostic.message))

            service_config = response.serviceConfig
        else:
            # If not Swagger, assume that we are dealing with Google Service Config
            service_config = encoding.JsonToMessage(
                self.services_messages.Service, config_contents)

        managed_service = self.services_messages.ManagedService(
            serviceConfig=service_config, serviceName=service_config.name)

        # Set the serviceConfig producerProjectId if it is not already set
        if not managed_service.serviceConfig.producerProjectId:
            managed_service.serviceConfig.producerProjectId = self.project

        request = self.services_messages.ServicemanagementServicesUpdateRequest(
            serviceName=managed_service.serviceName,
            managedService=managed_service,
        )

        try:
            result = self.services_client.services.Update(request)
        except apitools_exceptions.HttpError as error:
            raise exceptions.HttpException(services_util.GetError(error))

        # Remove the response portion of the resulting operation since
        # it can be extremely large.
        result.response = None

        return services_util.ProcessOperationResult(result)
Beispiel #6
0
def PushServiceConfig(swagger_file, project, client, messages):
    """Pushes Service Configuration to Google Service Management.

  Args:
    swagger_file: full path to a JSON file containing the swagger spec.
    project: the Google cloud project Id
    client: the client to use for calls to Service Management API
    messages: the client library messages to use for Service Management API

  Raises:
    SwaggerOpenException: if input is malformed or file cannot be read
    SwaggerUploadException: if service fails to convert swagger, or
      upload of the service configuration conversion result fails
    ValueError: if the required inputs are not provided.

  Returns:
    EndpointsServiceInfo: an instance of EndpointsServiceInfo that contains the
      Endpoints service name and service version that is pushed.
  """
    if not swagger_file:
        raise ValueError(
            'Open API (Swagger) specification file path must be provided.')
    if not project:
        raise ValueError('Project Id must be provided.')
    if not client:
        raise ValueError('Service Management client must be provided.')
    if not messages:
        raise ValueError(
            'Service Management client messages must be provided.')

    swagger_file_contents = None
    try:
        with open(swagger_file) as f:
            swagger_file_contents = f.read()
    except IOError:
        raise SwaggerOpenException(
            'Unable to read swagger spec file "{0}"'.format(swagger_file))

    # Try to load the file as JSON or YAML.
    service_config_dict = services_util.LoadJsonOrYaml(swagger_file_contents)
    if not service_config_dict:
        raise SwaggerOpenException(
            'Could not read JSON or YAML from Open API (Swagger) file {}.'.
            format(swagger_file))

    # Check to see if the Endpoints meta service needs to be enabled.
    enable_api.EnableServiceIfDisabled(project,
                                       services_util.GetEndpointsServiceName(),
                                       async=False)

    service_name = service_config_dict.get('host', None)
    # Create the Service resource if it does not already exist.
    services_util.CreateServiceIfNew(service_name, project)

    # Push the service configuration.
    push_config_result = services_util.PushOpenApiServiceConfig(
        service_name,
        swagger_file_contents,
        os.path.basename(swagger_file),
        async=False)
    config_id = services_util.GetServiceConfigIdFromSubmitConfigSourceResponse(
        push_config_result)

    if config_id and service_name:
        # Print this to screen and to the log because the output is needed by the
        # human user.
        log.status.Print(
            ('\nService Configuration with version [{0}] uploaded '
             'for service [{1}]\n').format(config_id, service_name))
    else:
        raise SwaggerUploadException(
            'Failed to retrieve Service Configuration Version')

    # Create a Rollout for the new service configuration
    percentages = messages.TrafficPercentStrategy.PercentagesValue()
    percentages.additionalProperties.append(
        messages.TrafficPercentStrategy.PercentagesValue.AdditionalProperty(
            key=config_id, value=100.0))
    traffic_percent_strategy = messages.TrafficPercentStrategy(
        percentages=percentages)
    rollout = messages.Rollout(
        serviceName=service_name,
        trafficPercentStrategy=traffic_percent_strategy,
    )
    rollout_operation = client.services_rollouts.Create(rollout)
    services_util.ProcessOperationResult(rollout_operation, async=False)

    # Enable the service for the producer project if it is not already enabled
    enable_api.EnableServiceIfDisabled(project, service_name, async=False)

    return EndpointsServiceInfo(service_name=service_name,
                                service_version=config_id)
Beispiel #7
0
    def Run(self, args):
        """Run 'service-management deploy'.

    Args:
      args: argparse.Namespace, The arguments that this command was invoked
          with.

    Returns:
      The response from the Update API call.

    Raises:
      SwaggerUploadException: if the provided service configuration files are
          rejected by the Service Management API.

      BadFileExceptionn: if the provided service configuration files are
          invalid or cannot be read.
    """
        messages = services_util.GetMessagesModule()
        client = services_util.GetClientInstance()

        file_types = messages.ConfigFile.FileTypeValueValuesEnum
        self.service_name = self.service_version = config_contents = None
        config_files = []

        for service_config_file in args.service_config_file:
            config_contents = None
            try:
                with open(service_config_file, 'r') as f:
                    config_contents = f.read()
            except IOError as ex:
                raise calliope_exceptions.BadFileException(
                    'Could not open service config file [{0}]: {1}'.format(
                        service_config_file, ex))

            if self.FilenameMatchesExtension(service_config_file,
                                             ['.json', '.yaml', '.yml']):
                # Try to load the file as JSON. If that fails, try YAML.
                service_config_dict = services_util.LoadJsonOrYaml(
                    config_contents)
                if not service_config_dict:
                    raise calliope_exceptions.BadFileException(
                        'Could not read JSON or YAML from service config file '
                        '[{0}].'.format(service_config_file))

                if 'swagger' in service_config_dict:
                    if not self.service_name:
                        self.service_name = service_config_dict.get(
                            'host', None)

                    # Always use YAML for Open API because JSON is a subset of YAML.
                    config_files.append(
                        self.MakeConfigFile(config_contents,
                                            service_config_file,
                                            file_types.OPEN_API_YAML))
                elif service_config_dict.get('type') == 'google.api.Service':
                    self.service_name = service_config_dict.get('name')

                    config_files.append(
                        self.MakeConfigFile(config_contents,
                                            service_config_file,
                                            file_types.SERVICE_CONFIG_YAML))
                elif 'name' in service_config_dict:
                    # This is a special case. If we have been provided a Google Service
                    # Configuration file which has a service 'name' field, but no 'type'
                    # field, we have to assume that this is a normalized service config,
                    # and can be uploaded via the CreateServiceConfig API. Therefore,
                    # we can short circute the process here.
                    if len(args.service_config_file) > 1:
                        raise calliope_exceptions.BadFileException((
                            'Ambiguous input. Found normalized service configuration in '
                            'file [{0}], but received multiple input files. To upload '
                            'normalized service config, please provide it separately from '
                            'other input files to avoid ambiguity.'
                        ).format(service_config_file))

                    self.service_name = service_config_dict.get('name', None)
                    config_files = []
                    break
                else:
                    raise calliope_exceptions.BadFileException((
                        'Unable to parse Open API, or Google Service Configuration '
                        'specification from {0}').format(service_config_file))

            elif self.FilenameMatchesExtension(service_config_file,
                                               ['.pb', '.descriptor']):
                config_files.append(
                    self.MakeConfigFile(config_contents, service_config_file,
                                        file_types.FILE_DESCRIPTOR_SET_PROTO))
            else:
                raise calliope_exceptions.BadFileException((
                    'Could not determine the content type of file [{0}]. Supported '
                    'extensions are .json .yaml .yml .pb. and .descriptor'
                ).format(service_config_file))

        # Check to see if the Endpoints meta service needs to be enabled.
        enable_api.EnableServiceIfDisabled(
            properties.VALUES.core.project.Get(required=True),
            services_util.GetEndpointsServiceName(), args. async)
        # Check if we need to create the service.
        services_util.CreateServiceIfNew(
            self.service_name,
            properties.VALUES.core.project.Get(required=True))

        if config_files:
            self.service_config_id = services_util.PushMultipleServiceConfigFiles(
                self.service_name, config_files, args. async)
        else:
            self.service_config_id = services_util.PushNormalizedGoogleServiceConfig(
                self.service_name,
                properties.VALUES.core.project.Get(required=True),
                config_contents)

        if not self.service_config_id:
            raise calliope_exceptions.ToolException(
                'Failed to retrieve Service Configuration Id.')

        # Create a Rollout for the new service configuration
        percentages = messages.TrafficPercentStrategy.PercentagesValue()
        percentages.additionalProperties.append(
            (messages.TrafficPercentStrategy.PercentagesValue.
             AdditionalProperty(key=self.service_config_id, value=100.0)))
        traffic_percent_strategy = messages.TrafficPercentStrategy(
            percentages=percentages)
        rollout = messages.Rollout(
            serviceName=self.service_name,
            trafficPercentStrategy=traffic_percent_strategy,
        )
        rollout_operation = client.services_rollouts.Create(rollout)
        services_util.ProcessOperationResult(rollout_operation, args. async)

        # Check to see if the service is already enabled
        enable_api.EnableServiceIfDisabled(
            properties.VALUES.core.project.Get(required=True),
            self.service_name, args. async)