From 10ec5044a691591339cf06f41b582209a19892bd Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 11:27:07 -0700 Subject: [PATCH 01/14] Generate recommender. --- recommender/.coveragerc | 19 + recommender/.flake8 | 14 + recommender/CHANGELOG.md | 5 + recommender/MANIFEST.in | 5 + recommender/README.rst | 80 ++++ recommender/docs/README.rst | 1 + recommender/docs/changelog.md | 1 + recommender/docs/conf.py | 359 ++++++++++++++++ recommender/docs/index.rst | 19 + .../docs/recommender_v1beta1/services.rst | 8 + .../docs/recommender_v1beta1/types.rst | 10 + .../google/cloud/recommender/__init__.py | 47 +++ recommender/google/cloud/recommender/py.typed | 2 + .../cloud/recommender_v1beta1/__init__.py | 33 ++ .../google/cloud/recommender_v1beta1/py.typed | 2 + .../recommender_v1beta1/services/__init__.py | 1 + .../services/recommender/__init__.py | 4 + .../services/recommender/client.py | 395 ++++++++++++++++++ .../services/recommender/pagers.py | 67 +++ .../recommender/transports/__init__.py | 14 + .../services/recommender/transports/base.py | 91 ++++ .../services/recommender/transports/grpc.py | 258 ++++++++++++ .../types/recommendation.py | 275 ++++++++++++ .../types/recommender_service.py | 183 ++++++++ recommender/mypy.ini | 3 + recommender/noxfile.py | 160 +++++++ recommender/setup.cfg | 3 + recommender/setup.py | 29 ++ recommender/synth.metadata | 31 ++ recommender/synth.py | 88 ++++ .../recommender_v1beta1/test_recommender.py | 345 +++++++++++++++ 31 files changed, 2552 insertions(+) create mode 100644 recommender/.coveragerc create mode 100644 recommender/.flake8 create mode 100644 recommender/CHANGELOG.md create mode 100644 recommender/MANIFEST.in create mode 100644 recommender/README.rst create mode 120000 recommender/docs/README.rst create mode 120000 recommender/docs/changelog.md create mode 100644 recommender/docs/conf.py create mode 100644 recommender/docs/index.rst create mode 100644 recommender/docs/recommender_v1beta1/services.rst create mode 100644 recommender/docs/recommender_v1beta1/types.rst create mode 100644 recommender/google/cloud/recommender/__init__.py create mode 100644 recommender/google/cloud/recommender/py.typed create mode 100644 recommender/google/cloud/recommender_v1beta1/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/py.typed create mode 100644 recommender/google/cloud/recommender_v1beta1/services/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/client.py create mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py create mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py create mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py create mode 100644 recommender/google/cloud/recommender_v1beta1/types/recommendation.py create mode 100644 recommender/google/cloud/recommender_v1beta1/types/recommender_service.py create mode 100644 recommender/mypy.ini create mode 100644 recommender/noxfile.py create mode 100644 recommender/setup.cfg create mode 100644 recommender/setup.py create mode 100644 recommender/synth.metadata create mode 100644 recommender/synth.py create mode 100644 recommender/tests/unit/recommender_v1beta1/test_recommender.py diff --git a/recommender/.coveragerc b/recommender/.coveragerc new file mode 100644 index 000000000000..b178b094aa1d --- /dev/null +++ b/recommender/.coveragerc @@ -0,0 +1,19 @@ +# Generated by synthtool. DO NOT EDIT! +[run] +branch = True + +[report] +fail_under = 100 +show_missing = True +exclude_lines = + # Re-enable the standard pragma + pragma: NO COVER + # Ignore debug-only repr + def __repr__ + # Ignore abstract methods + raise NotImplementedError +omit = + */gapic/*.py + */proto/*.py + */core/*.py + */site-packages/*.py \ No newline at end of file diff --git a/recommender/.flake8 b/recommender/.flake8 new file mode 100644 index 000000000000..0268ecc9c55c --- /dev/null +++ b/recommender/.flake8 @@ -0,0 +1,14 @@ +# Generated by synthtool. DO NOT EDIT! +[flake8] +ignore = E203, E266, E501, W503 +exclude = + # Exclude generated code. + **/proto/** + **/gapic/** + *_pb2.py + + # Standard linting exemptions. + __pycache__, + .git, + *.pyc, + conf.py diff --git a/recommender/CHANGELOG.md b/recommender/CHANGELOG.md new file mode 100644 index 000000000000..7459c5dea295 --- /dev/null +++ b/recommender/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +[PyPI History][1] + +[1]: https://pypi.org/project/google-cloud-recommender/#history \ No newline at end of file diff --git a/recommender/MANIFEST.in b/recommender/MANIFEST.in new file mode 100644 index 000000000000..9cbf175afe6b --- /dev/null +++ b/recommender/MANIFEST.in @@ -0,0 +1,5 @@ +include README.rst LICENSE +recursive-include google *.json *.proto +recursive-include tests * +global-exclude *.py[co] +global-exclude __pycache__ diff --git a/recommender/README.rst b/recommender/README.rst new file mode 100644 index 000000000000..225d86d9e514 --- /dev/null +++ b/recommender/README.rst @@ -0,0 +1,80 @@ +Python Client for Cloud Recommender API +============================================= + +|alpha| |pypi| |versions| + +- `Client Library Documentation`_ +- `Product Documentation`_ + +.. |alpha| image:: https://img.shields.io/badge/support-alpha-orange.svg + :target: https://github.com/googleapis/google-cloud-python/blob/master/README.rst#alpha-support +.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-recommender.svg + :target: https://pypi.org/project/google-cloud-recommender/ +.. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-recommender.svg + :target: https://pypi.org/project/google-cloud-recommender/ +.. _Cloud Recommender API: https://cloud.google.com/recommendations-ai/ +.. _Client Library Documentation: https://googleapis.dev/python/recommender/latest +.. _Product Documentation: https://cloud.google.com/recommendations-ai/docs/ + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. `Enable the Cloud Recommender API.`_ +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Enable the Cloud Recommender API.: https://cloud.google.com/Recommender +.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. + +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ + + +Supported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ +Python >= 3.5 + + +Mac/Linux +^^^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + source /bin/activate + /bin/pip install google-cloud-recommender + + +Windows +^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + \Scripts\activate + \Scripts\pip.exe install google-cloud-recommender + +Next Steps +~~~~~~~~~~ + +- Read the `Client Library Documentation`_ for Cloud Recommender API + API to see other available methods on the client. +- Read the `Product documentation`_ to learn + more about the product and see How-to Guides. \ No newline at end of file diff --git a/recommender/docs/README.rst b/recommender/docs/README.rst new file mode 120000 index 000000000000..89a0106941ff --- /dev/null +++ b/recommender/docs/README.rst @@ -0,0 +1 @@ +../README.rst \ No newline at end of file diff --git a/recommender/docs/changelog.md b/recommender/docs/changelog.md new file mode 120000 index 000000000000..04c99a55caae --- /dev/null +++ b/recommender/docs/changelog.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/recommender/docs/conf.py b/recommender/docs/conf.py new file mode 100644 index 000000000000..9cd1b152279a --- /dev/null +++ b/recommender/docs/conf.py @@ -0,0 +1,359 @@ +# -*- coding: utf-8 -*- +# +# google-cloud-recommender documentation build configuration file +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath("..")) + +__version__ = "0.1.0" + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.6.3" + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.coverage", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", +] + +# autodoc/autosummary flags +autoclass_content = "both" +autodoc_default_flags = ["members"] +autosummary_generate = True + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# Allow markdown includes (so releases.md can include CHANGLEOG.md) +# http://www.sphinx-doc.org/en/master/markdown.html +source_parsers = {".md": "recommonmark.parser.CommonMarkParser"} + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = u"google-cloud-recommender" +copyright = u"2017, Google" +author = u"Google APIs" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The full version, including alpha/beta/rc tags. +release = __version__ +# The short X.Y version. +version = ".".join(release.split(".")[0:2]) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# today = '' +# Else, today_fmt is used as the format for a strftime call. +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["_build"] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = "alabaster" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + "description": "Google Cloud Client Libraries for Python", + "github_user": "googleapis", + "github_repo": "google-cloud-python", + "github_banner": True, + "font_family": "'Roboto', Georgia, sans", + "head_font_family": "'Roboto', Georgia, serif", + "code_font_family": "'Roboto Mono', 'Consolas', monospace", +} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +# html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +# html_static_path = [] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +# html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# html_additional_pages = {} + +# If false, no module index is generated. +# html_domain_indices = True + +# If false, no index is generated. +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = "google-cloud-recommender-doc" + +# -- Options for warnings ------------------------------------------------------ + + +suppress_warnings = [ + # Temporarily suppress this to avoid "more than one target found for + # cross-reference" warning, which are intractable for us to avoid while in + # a mono-repo. + # See https://github.com/sphinx-doc/sphinx/blob + # /2a65ffeef5c107c19084fabdd706cdff3f52d93c/sphinx/domains/python.py#L843 + "ref.python" +] + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + #'preamble': '', + # Latex figure (float) alignment + #'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + master_doc, + "google-cloud-recommender.tex", + u"google-cloud-recommender Documentation", + author, + "manual", + ) +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# latex_use_parts = False + +# If true, show page references after internal links. +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# latex_appendices = [] + +# If false, no module index is generated. +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + master_doc, + "google-cloud-recommender", + u"google-cloud-recommender Documentation", + [author], + 1, + ) +] + +# If true, show URL addresses after external links. +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + master_doc, + "google-cloud-recommender", + u"google-cloud-recommender Documentation", + author, + "google-cloud-recommender", + "GAPIC library for the {metadata.shortName} v2 service", + "APIs", + ) +] + +# Documents to append as an appendix to all manuals. +# texinfo_appendices = [] + +# If false, no module index is generated. +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + "python": ("http://python.readthedocs.org/en/latest/", None), + "google-auth": ("https://google-auth.readthedocs.io/en/stable", None), + "google.api_core": ("https://googleapis.dev/python/google-api-core/latest", None), + "grpc": ("https://grpc.io/grpc/python/", None), + "requests": ("https://2.python-requests.org/en/master/", None), +} + + +# Napoleon settings +napoleon_google_docstring = True +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = False +napoleon_include_special_with_doc = True +napoleon_use_admonition_for_examples = False +napoleon_use_admonition_for_notes = False +napoleon_use_admonition_for_references = False +napoleon_use_ivar = False +napoleon_use_param = True +napoleon_use_rtype = True diff --git a/recommender/docs/index.rst b/recommender/docs/index.rst new file mode 100644 index 000000000000..a16e9b57f67f --- /dev/null +++ b/recommender/docs/index.rst @@ -0,0 +1,19 @@ +.. include:: README.rst + +Api Reference +------------- +.. toctree:: + :maxdepth: 2 + + recommender_v1beta1/services + recommender_v1beta1/types + +Changelog +--------- + +For a list of all ``google-cloud-recommender`` releases: + +.. toctree:: + :maxdepth: 2 + + changelog \ No newline at end of file diff --git a/recommender/docs/recommender_v1beta1/services.rst b/recommender/docs/recommender_v1beta1/services.rst new file mode 100644 index 000000000000..e413521826f1 --- /dev/null +++ b/recommender/docs/recommender_v1beta1/services.rst @@ -0,0 +1,8 @@ +Client for Cloud Recommender API +=============================================== + +.. automodule:: google.cloud.recommender_v1beta1.services.recommender.client + :members: + +.. automodule:: google.cloud.recommender_v1beta1.services.recommender.pagers + :members: \ No newline at end of file diff --git a/recommender/docs/recommender_v1beta1/types.rst b/recommender/docs/recommender_v1beta1/types.rst new file mode 100644 index 000000000000..1bc5dca6500c --- /dev/null +++ b/recommender/docs/recommender_v1beta1/types.rst @@ -0,0 +1,10 @@ +Types for Cloud Recommender API +=============================================== + +.. automodule:: google.cloud.recommender_v1beta1.types.recommendation + :members: + :undoc-members: + +.. automodule:: google.cloud.recommender_v1beta1.types.recommender_service + :members: + :undoc-members: \ No newline at end of file diff --git a/recommender/google/cloud/recommender/__init__.py b/recommender/google/cloud/recommender/__init__.py new file mode 100644 index 000000000000..35baf54bdf29 --- /dev/null +++ b/recommender/google/cloud/recommender/__init__.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +from google.cloud.recommender_v1beta1.services.recommender.client import Recommender +from google.cloud.recommender_v1beta1.types.recommendation import CostProjection +from google.cloud.recommender_v1beta1.types.recommendation import Impact +from google.cloud.recommender_v1beta1.types.recommendation import Operation +from google.cloud.recommender_v1beta1.types.recommendation import OperationGroup +from google.cloud.recommender_v1beta1.types.recommendation import Recommendation +from google.cloud.recommender_v1beta1.types.recommendation import RecommendationContent +from google.cloud.recommender_v1beta1.types.recommendation import ( + RecommendationStateInfo, +) +from google.cloud.recommender_v1beta1.types.recommender_service import ( + GetRecommendationRequest, +) +from google.cloud.recommender_v1beta1.types.recommender_service import ( + ListRecommendationsRequest, +) +from google.cloud.recommender_v1beta1.types.recommender_service import ( + ListRecommendationsResponse, +) +from google.cloud.recommender_v1beta1.types.recommender_service import ( + MarkRecommendationClaimedRequest, +) +from google.cloud.recommender_v1beta1.types.recommender_service import ( + MarkRecommendationFailedRequest, +) +from google.cloud.recommender_v1beta1.types.recommender_service import ( + MarkRecommendationSucceededRequest, +) + + +__all__ = ( + "Recommender", + "CostProjection", + "Impact", + "Operation", + "OperationGroup", + "Recommendation", + "RecommendationContent", + "RecommendationStateInfo", + "GetRecommendationRequest", + "ListRecommendationsRequest", + "ListRecommendationsResponse", + "MarkRecommendationClaimedRequest", + "MarkRecommendationFailedRequest", + "MarkRecommendationSucceededRequest", +) diff --git a/recommender/google/cloud/recommender/py.typed b/recommender/google/cloud/recommender/py.typed new file mode 100644 index 000000000000..f9105be894e2 --- /dev/null +++ b/recommender/google/cloud/recommender/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-recommender package uses inline types. diff --git a/recommender/google/cloud/recommender_v1beta1/__init__.py b/recommender/google/cloud/recommender_v1beta1/__init__.py new file mode 100644 index 000000000000..cb8f79f143c4 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/__init__.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +from .services.recommender import Recommender +from .types.recommendation import CostProjection +from .types.recommendation import Impact +from .types.recommendation import Operation +from .types.recommendation import OperationGroup +from .types.recommendation import Recommendation +from .types.recommendation import RecommendationContent +from .types.recommendation import RecommendationStateInfo +from .types.recommender_service import GetRecommendationRequest +from .types.recommender_service import ListRecommendationsRequest +from .types.recommender_service import ListRecommendationsResponse +from .types.recommender_service import MarkRecommendationClaimedRequest +from .types.recommender_service import MarkRecommendationFailedRequest +from .types.recommender_service import MarkRecommendationSucceededRequest + + +__all__ = ( + "CostProjection", + "GetRecommendationRequest", + "Impact", + "ListRecommendationsRequest", + "ListRecommendationsResponse", + "MarkRecommendationClaimedRequest", + "MarkRecommendationFailedRequest", + "MarkRecommendationSucceededRequest", + "Operation", + "OperationGroup", + "Recommendation", + "RecommendationContent", + "RecommendationStateInfo", + "Recommender", +) diff --git a/recommender/google/cloud/recommender_v1beta1/py.typed b/recommender/google/cloud/recommender_v1beta1/py.typed new file mode 100644 index 000000000000..f9105be894e2 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/py.typed @@ -0,0 +1,2 @@ +# Marker file for PEP 561. +# The google-cloud-recommender package uses inline types. diff --git a/recommender/google/cloud/recommender_v1beta1/services/__init__.py b/recommender/google/cloud/recommender_v1beta1/services/__init__.py new file mode 100644 index 000000000000..40a96afc6ff0 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py new file mode 100644 index 000000000000..e0016832d0fb --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +from .client import Recommender + +__all__ = ("Recommender",) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/client.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/client.py new file mode 100644 index 000000000000..92316afb4752 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/recommender/client.py @@ -0,0 +1,395 @@ +# -*- coding: utf-8 -*- +from collections import OrderedDict +from typing import Dict, Sequence, Tuple, Type, Union +import pkg_resources + +from google.api_core import exceptions # type: ignore +from google.api_core import gapic_v1 # type: ignore +from google.api_core import retry as retries # type: ignore +from google.auth import credentials # type: ignore + +from google.cloud.recommender_v1beta1.services.recommender import pagers +from google.cloud.recommender_v1beta1.types import recommendation +from google.cloud.recommender_v1beta1.types import recommender_service + +from .transports.base import RecommenderTransport +from .transports.grpc import RecommenderGrpcTransport + + +class RecommenderMeta(type): + """Metaclass for the Recommender client. + + This provides class-level methods for building and retrieving + support objects (e.g. transport) without polluting the client instance + objects. + """ + + _transport_registry = OrderedDict() # type: Dict[str, Type[RecommenderTransport]] + _transport_registry["grpc"] = RecommenderGrpcTransport + + def get_transport_class(cls, label: str = None) -> Type[RecommenderTransport]: + """Return an appropriate transport class. + + Args: + label: The name of the desired transport. If none is + provided, then the first transport in the registry is used. + + Returns: + The transport class to use. + """ + # If a specific transport is requested, return that one. + if label: + return cls._transport_registry[label] + + # No transport is requested; return the default (that is, the first one + # in the dictionary). + return next(iter(cls._transport_registry.values())) + + +class Recommender(metaclass=RecommenderMeta): + """Provides recommendations for cloud customers for various + categories like performance optimization, cost savings, + reliability, feature discovery, etc. These recommendations are + generated automatically based on analysis of user resources, + configuration and monitoring metrics. + """ + + def __init__( + self, + *, + host: str = "recommender.googleapis.com", + credentials: credentials.Credentials = None, + transport: Union[str, RecommenderTransport] = None + ) -> None: + """Instantiate the recommender. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + transport (Union[str, ~.RecommenderTransport]): The + transport to use. If set to None, a transport is chosen + automatically. + """ + # Save or instantiate the transport. + # Ordinarily, we provide the transport, but allowing a custom transport + # instance provides an extensibility point for unusual situations. + if isinstance(transport, RecommenderTransport): + if credentials: + raise ValueError( + "When providing a transport instance, " + "provide its credentials directly." + ) + self._transport = transport + else: + Transport = type(self).get_transport_class(transport) + self._transport = Transport(credentials=credentials, host=host) + + def list_recommendations( + self, + request: recommender_service.ListRecommendationsRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = () + ) -> pagers.ListRecommendationsPager: + r"""Lists recommendations for a Cloud project. Requires the + recommender.*.list IAM permission for the specified recommender. + + Args: + request (:class:`~.recommender_service.ListRecommendationsRequest`): + The request object. Request for the + `ListRecommendations` method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.pagers.ListRecommendationsPager: + Response to the ``ListRecommendations`` method. + + Iterating over this object will yield results and + resolve additional pages automatically. + + """ + # Create or coerce a protobuf request object. + request = recommender_service.ListRecommendationsRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.list_recommendations, + default_retry=retries.Retry( + predicate=retries.if_exception_type( + exceptions.Aborted, + exceptions.ServiceUnavailable, + exceptions.Unknown, + ) + ), + default_timeout=None, + client_info=_client_info, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) + + # This method is paged; wrap the response in a pager, which provides + # an `__iter__` convenience method. + response = pagers.ListRecommendationsPager( + method=rpc, request=request, response=response + ) + + # Done; return the response. + return response + + def get_recommendation( + self, + request: recommender_service.GetRecommendationRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = () + ) -> recommendation.Recommendation: + r"""Gets the requested recommendation. Requires the + recommender.*.get IAM permission for the specified recommender. + + Args: + request (:class:`~.recommender_service.GetRecommendationRequest`): + The request object. Request to the `GetRecommendation` + method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.recommendation.Recommendation: + A recommendation along with a + suggested action. E.g., a rightsizing + recommendation for an underutilized VM, + IAM role recommendations, etc + + """ + # Create or coerce a protobuf request object. + request = recommender_service.GetRecommendationRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.get_recommendation, + default_retry=retries.Retry( + predicate=retries.if_exception_type( + exceptions.Aborted, + exceptions.ServiceUnavailable, + exceptions.Unknown, + ) + ), + default_timeout=None, + client_info=_client_info, + ) + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) + + # Done; return the response. + return response + + def mark_recommendation_claimed( + self, + request: recommender_service.MarkRecommendationClaimedRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = () + ) -> recommendation.Recommendation: + r"""Mark the Recommendation State as Claimed. Users can use this + method to indicate to the Recommender API that they are starting + to apply the recommendation themselves. This stops the + recommendation content from being updated. + + MarkRecommendationClaimed can be applied to recommendations in + CLAIMED, SUCCEEDED, FAILED, or ACTIVE state. + + Requires the recommender.*.update IAM permission for the + specified recommender. + + Args: + request (:class:`~.recommender_service.MarkRecommendationClaimedRequest`): + The request object. Request for the + `MarkRecommendationClaimed` Method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.recommendation.Recommendation: + A recommendation along with a + suggested action. E.g., a rightsizing + recommendation for an underutilized VM, + IAM role recommendations, etc + + """ + # Create or coerce a protobuf request object. + request = recommender_service.MarkRecommendationClaimedRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.mark_recommendation_claimed, + default_retry=retries.Retry( + predicate=retries.if_exception_type(exceptions.ServiceUnavailable) + ), + default_timeout=None, + client_info=_client_info, + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) + + # Done; return the response. + return response + + def mark_recommendation_succeeded( + self, + request: recommender_service.MarkRecommendationSucceededRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = () + ) -> recommendation.Recommendation: + r"""Mark the Recommendation State as Succeeded. Users can use this + method to indicate to the Recommender API that they have applied + the recommendation themselves, and the operation was successful. + This stops the recommendation content from being updated. + + MarkRecommendationSucceeded can be applied to recommendations in + ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.*.update IAM permission for the + specified recommender. + + Args: + request (:class:`~.recommender_service.MarkRecommendationSucceededRequest`): + The request object. Request for the + `MarkRecommendationSucceeded` Method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.recommendation.Recommendation: + A recommendation along with a + suggested action. E.g., a rightsizing + recommendation for an underutilized VM, + IAM role recommendations, etc + + """ + # Create or coerce a protobuf request object. + request = recommender_service.MarkRecommendationSucceededRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.mark_recommendation_succeeded, + default_retry=retries.Retry( + predicate=retries.if_exception_type(exceptions.ServiceUnavailable) + ), + default_timeout=None, + client_info=_client_info, + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) + + # Done; return the response. + return response + + def mark_recommendation_failed( + self, + request: recommender_service.MarkRecommendationFailedRequest = None, + *, + retry: retries.Retry = gapic_v1.method.DEFAULT, + timeout: float = None, + metadata: Sequence[Tuple[str, str]] = () + ) -> recommendation.Recommendation: + r"""Mark the Recommendation State as Failed. Users can use this + method to indicate to the Recommender API that they have applied + the recommendation themselves, and the operation failed. This + stops the recommendation content from being updated. + + MarkRecommendationFailed can be applied to recommendations in + ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.*.update IAM permission for the + specified recommender. + + Args: + request (:class:`~.recommender_service.MarkRecommendationFailedRequest`): + The request object. Request for the + `MarkRecommendationFailed` Method. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.recommendation.Recommendation: + A recommendation along with a + suggested action. E.g., a rightsizing + recommendation for an underutilized VM, + IAM role recommendations, etc + + """ + # Create or coerce a protobuf request object. + request = recommender_service.MarkRecommendationFailedRequest(request) + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = gapic_v1.method.wrap_method( + self._transport.mark_recommendation_failed, + default_retry=retries.Retry( + predicate=retries.if_exception_type(exceptions.ServiceUnavailable) + ), + default_timeout=None, + client_info=_client_info, + ) + + # Send the request. + response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) + + # Done; return the response. + return response + + +try: + _client_info = gapic_v1.client_info.ClientInfo( + gapic_version=pkg_resources.get_distribution("google-cloud-recommender").version + ) +except pkg_resources.DistributionNotFound: + _client_info = gapic_v1.client_info.ClientInfo() + + +__all__ = ("Recommender",) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py new file mode 100644 index 000000000000..153ecb198b15 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +from typing import Any, Callable, Iterable + +from google.cloud.recommender_v1beta1.types import recommendation +from google.cloud.recommender_v1beta1.types import recommender_service + + +class ListRecommendationsPager: + """A pager for iterating through ``list_recommendations`` requests. + + This class thinly wraps an initial + :class:`~.recommender_service.ListRecommendationsResponse` object, and + provides an ``__iter__`` method to iterate through its + ``recommendations`` field. + + If there are more pages, the ``__iter__`` method will make additional + ``ListRecommendations`` requests and continue to iterate + through the ``recommendations`` field on the + corresponding responses. + + All the usual :class:`~.recommender_service.ListRecommendationsResponse` + attributes are available on the pager. If multiple requests are made, only + the most recent response is retained, and thus used for attribute lookup. + """ + + def __init__( + self, + method: Callable[ + [recommender_service.ListRecommendationsRequest], + recommender_service.ListRecommendationsResponse, + ], + request: recommender_service.ListRecommendationsRequest, + response: recommender_service.ListRecommendationsResponse, + ): + """Instantiate the pager. + + Args: + method (Callable): The method that was originally called, and + which instantiated this pager. + request (:class:`~.recommender_service.ListRecommendationsRequest`): + The initial request object. + response (:class:`~.recommender_service.ListRecommendationsResponse`): + The initial response object. + """ + self._method = method + self._request = recommender_service.ListRecommendationsRequest(request) + self._response = response + + def __getattr__(self, name: str) -> Any: + return getattr(self._response, name) + + def __iter__(self) -> Iterable[recommendation.Recommendation]: + while True: + # Iterate through the results on this response. + for result in self._response.recommendations: + yield result + + # Sanity check: Is this the last page? If so, we are done. + if not self._response.next_page_token: + break + + # Get the next page. + self._request.page_token = self._response.next_page_token + self._response = self._method(self._request) + + def __repr__(self) -> str: + return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py new file mode 100644 index 000000000000..ccda47244c80 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from collections import OrderedDict +from typing import Dict, Type + +from .base import RecommenderTransport +from .grpc import RecommenderGrpcTransport + + +# Compile a registry of transports. +_transport_registry = OrderedDict() # type: Dict[str, Type[RecommenderTransport]] +_transport_registry["grpc"] = RecommenderGrpcTransport + + +__all__ = ("RecommenderTransport", "RecommenderGrpcTransport") diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py new file mode 100644 index 000000000000..da92f77fed38 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +import abc +import typing + +from google import auth +from google.auth import credentials # type: ignore + +from google.cloud.recommender_v1beta1.types import recommendation +from google.cloud.recommender_v1beta1.types import recommender_service + + +class RecommenderTransport(metaclass=abc.ABCMeta): + """Abstract transport class for Recommender.""" + + AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + def __init__( + self, + *, + host: str = "recommender.googleapis.com", + credentials: credentials.Credentials = None + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + """ + # Save the hostname. Default to port 443 (HTTPS) if none is specified. + if ":" not in host: + host += ":443" + self._host = host + + # If no credentials are provided, then determine the appropriate + # defaults. + if credentials is None: + credentials, _ = auth.default(scopes=self.AUTH_SCOPES) + + # Save the credentials. + self._credentials = credentials + + @property + def list_recommendations( + self + ) -> typing.Callable[ + [recommender_service.ListRecommendationsRequest], + recommender_service.ListRecommendationsResponse, + ]: + raise NotImplementedError + + @property + def get_recommendation( + self + ) -> typing.Callable[ + [recommender_service.GetRecommendationRequest], recommendation.Recommendation + ]: + raise NotImplementedError + + @property + def mark_recommendation_claimed( + self + ) -> typing.Callable[ + [recommender_service.MarkRecommendationClaimedRequest], + recommendation.Recommendation, + ]: + raise NotImplementedError + + @property + def mark_recommendation_succeeded( + self + ) -> typing.Callable[ + [recommender_service.MarkRecommendationSucceededRequest], + recommendation.Recommendation, + ]: + raise NotImplementedError + + @property + def mark_recommendation_failed( + self + ) -> typing.Callable[ + [recommender_service.MarkRecommendationFailedRequest], + recommendation.Recommendation, + ]: + raise NotImplementedError + + +__all__ = ("RecommenderTransport",) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py new file mode 100644 index 000000000000..f9c449266a2e --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- +from typing import Callable, Dict + +from google.api_core import grpc_helpers # type: ignore +from google.auth import credentials # type: ignore + +import grpc # type: ignore + +from google.cloud.recommender_v1beta1.types import recommendation +from google.cloud.recommender_v1beta1.types import recommender_service + +from .base import RecommenderTransport + + +class RecommenderGrpcTransport(RecommenderTransport): + """gRPC backend transport for Recommender. + + Provides recommendations for cloud customers for various + categories like performance optimization, cost savings, + reliability, feature discovery, etc. These recommendations are + generated automatically based on analysis of user resources, + configuration and monitoring metrics. + + This class defines the same methods as the primary client, so the + primary client can load the underlying transport implementation + and call it. + + It sends protocol buffers over the wire using gRPC (which is built on + top of HTTP/2); the ``grpcio`` package must be installed. + """ + + def __init__( + self, + *, + host: str = "recommender.googleapis.com", + credentials: credentials.Credentials = None, + channel: grpc.Channel = None + ) -> None: + """Instantiate the transport. + + Args: + host (Optional[str]): The hostname to connect to. + credentials (Optional[google.auth.credentials.Credentials]): The + authorization credentials to attach to requests. These + credentials identify the application to the service; if none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is ignored if ``channel`` is provided. + channel (Optional[grpc.Channel]): A ``Channel`` instance through + which to make calls. + """ + # Sanity check: Ensure that channel and credentials are not both + # provided. + if channel: + credentials = False + + # Run the base constructor. + super().__init__(host=host, credentials=credentials) + self._stubs = {} # type: Dict[str, Callable] + + # If a channel was explicitly provided, set it. + if channel: + self._grpc_channel = channel + + @property + def grpc_channel(self) -> grpc.Channel: + """Create the channel designed to connect to this service. + + This property caches on the instance; repeated calls return + the same channel. + """ + # Sanity check: Only create a new channel if we do not already + # have one. + if not hasattr(self, "_grpc_channel"): + self._grpc_channel = grpc_helpers.create_channel( + self._host, credentials=self._credentials, scopes=self.AUTH_SCOPES + ) + + # Return the channel from cache. + return self._grpc_channel + + @property + def list_recommendations( + self + ) -> Callable[ + [recommender_service.ListRecommendationsRequest], + recommender_service.ListRecommendationsResponse, + ]: + r"""Return a callable for the list recommendations method over gRPC. + + Lists recommendations for a Cloud project. Requires the + recommender.*.list IAM permission for the specified recommender. + + Returns: + Callable[[~.ListRecommendationsRequest], + ~.ListRecommendationsResponse]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "list_recommendations" not in self._stubs: + self._stubs["list_recommendations"] = self.grpc_channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/ListRecommendations", + request_serializer=recommender_service.ListRecommendationsRequest.serialize, + response_deserializer=recommender_service.ListRecommendationsResponse.deserialize, + ) + return self._stubs["list_recommendations"] + + @property + def get_recommendation( + self + ) -> Callable[ + [recommender_service.GetRecommendationRequest], recommendation.Recommendation + ]: + r"""Return a callable for the get recommendation method over gRPC. + + Gets the requested recommendation. Requires the + recommender.*.get IAM permission for the specified recommender. + + Returns: + Callable[[~.GetRecommendationRequest], + ~.Recommendation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "get_recommendation" not in self._stubs: + self._stubs["get_recommendation"] = self.grpc_channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/GetRecommendation", + request_serializer=recommender_service.GetRecommendationRequest.serialize, + response_deserializer=recommendation.Recommendation.deserialize, + ) + return self._stubs["get_recommendation"] + + @property + def mark_recommendation_claimed( + self + ) -> Callable[ + [recommender_service.MarkRecommendationClaimedRequest], + recommendation.Recommendation, + ]: + r"""Return a callable for the mark recommendation claimed method over gRPC. + + Mark the Recommendation State as Claimed. Users can use this + method to indicate to the Recommender API that they are starting + to apply the recommendation themselves. This stops the + recommendation content from being updated. + + MarkRecommendationClaimed can be applied to recommendations in + CLAIMED, SUCCEEDED, FAILED, or ACTIVE state. + + Requires the recommender.*.update IAM permission for the + specified recommender. + + Returns: + Callable[[~.MarkRecommendationClaimedRequest], + ~.Recommendation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "mark_recommendation_claimed" not in self._stubs: + self._stubs["mark_recommendation_claimed"] = self.grpc_channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationClaimed", + request_serializer=recommender_service.MarkRecommendationClaimedRequest.serialize, + response_deserializer=recommendation.Recommendation.deserialize, + ) + return self._stubs["mark_recommendation_claimed"] + + @property + def mark_recommendation_succeeded( + self + ) -> Callable[ + [recommender_service.MarkRecommendationSucceededRequest], + recommendation.Recommendation, + ]: + r"""Return a callable for the mark recommendation succeeded method over gRPC. + + Mark the Recommendation State as Succeeded. Users can use this + method to indicate to the Recommender API that they have applied + the recommendation themselves, and the operation was successful. + This stops the recommendation content from being updated. + + MarkRecommendationSucceeded can be applied to recommendations in + ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.*.update IAM permission for the + specified recommender. + + Returns: + Callable[[~.MarkRecommendationSucceededRequest], + ~.Recommendation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "mark_recommendation_succeeded" not in self._stubs: + self._stubs[ + "mark_recommendation_succeeded" + ] = self.grpc_channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationSucceeded", + request_serializer=recommender_service.MarkRecommendationSucceededRequest.serialize, + response_deserializer=recommendation.Recommendation.deserialize, + ) + return self._stubs["mark_recommendation_succeeded"] + + @property + def mark_recommendation_failed( + self + ) -> Callable[ + [recommender_service.MarkRecommendationFailedRequest], + recommendation.Recommendation, + ]: + r"""Return a callable for the mark recommendation failed method over gRPC. + + Mark the Recommendation State as Failed. Users can use this + method to indicate to the Recommender API that they have applied + the recommendation themselves, and the operation failed. This + stops the recommendation content from being updated. + + MarkRecommendationFailed can be applied to recommendations in + ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.*.update IAM permission for the + specified recommender. + + Returns: + Callable[[~.MarkRecommendationFailedRequest], + ~.Recommendation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "mark_recommendation_failed" not in self._stubs: + self._stubs["mark_recommendation_failed"] = self.grpc_channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationFailed", + request_serializer=recommender_service.MarkRecommendationFailedRequest.serialize, + response_deserializer=recommendation.Recommendation.deserialize, + ) + return self._stubs["mark_recommendation_failed"] + + +__all__ = ("RecommenderGrpcTransport",) diff --git a/recommender/google/cloud/recommender_v1beta1/types/recommendation.py b/recommender/google/cloud/recommender_v1beta1/types/recommendation.py new file mode 100644 index 000000000000..bc55b7f9816e --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/types/recommendation.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +import proto # type: ignore + + +from google.protobuf import duration_pb2 as gp_duration # type: ignore +from google.protobuf import struct_pb2 as struct # type: ignore +from google.protobuf import timestamp_pb2 as timestamp # type: ignore +from google.type import money_pb2 as money # type: ignore + + +__protobuf__ = proto.module( + package="google.cloud.recommender.v1beta1", + manifest={ + "Recommendation", + "RecommendationContent", + "OperationGroup", + "Operation", + "CostProjection", + "Impact", + "RecommendationStateInfo", + }, +) + + +class Recommendation(proto.Message): + r"""A recommendation along with a suggested action. E.g., a + rightsizing recommendation for an underutilized VM, IAM role + recommendations, etc + + Attributes: + name (str): + Name of recommendation. + + A project recommendation is represented as + projects/[PROJECT_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER_ID]/recommendations/[RECOMMENDATION_ID] + description (str): + Free-form human readable summary in English. + The maximum length is 500 characters. + recommender_subtype (str): + Contains an identifier for a subtype of recommendations + produced for the same recommender. Subtype is a function of + content and impact, meaning a new subtype will be added when + either content or primary impact category changes. + + Examples: For recommender = + "google.iam.policy.RoleRecommender", recommender_subtype can + be one of "REMOVE_ROLE"/"REPLACE_ROLE". + last_refresh_time (~.timestamp.Timestamp): + Last time this recommendation was refreshed + by the system that created it in the first + place. + primary_impact (~.recommendation.Impact): + The primary impact that this recommendation + can have while trying to optimize for one + category. + additional_impact (Sequence[~.recommendation.Impact]): + Optional set of additional impact that this + recommendation may have when trying to optimize + for the primary category. These may be positive + or negative. + content (~.recommendation.RecommendationContent): + Content of the recommendation describing + recommended changes to resources. + state_info (~.recommendation.RecommendationStateInfo): + Information for state. Contains state and + metadata. + etag (str): + Fingerprint of the Recommendation. Provides + optimistic locking when updating states. + """ + name = proto.Field(proto.STRING, number=1) + description = proto.Field(proto.STRING, number=2) + recommender_subtype = proto.Field(proto.STRING, number=12) + last_refresh_time = proto.Field( + proto.MESSAGE, number=4, message=timestamp.Timestamp + ) + primary_impact = proto.Field(proto.MESSAGE, number=5, message="Impact") + additional_impact = proto.RepeatedField(proto.MESSAGE, number=6, message="Impact") + content = proto.Field(proto.MESSAGE, number=7, message="RecommendationContent") + state_info = proto.Field( + proto.MESSAGE, number=10, message="RecommendationStateInfo" + ) + etag = proto.Field(proto.STRING, number=11) + + +class RecommendationContent(proto.Message): + r"""Contains what resources are changing and how they are + changing. + + Attributes: + operation_groups (Sequence[~.recommendation.OperationGroup]): + Operations to one or more Google Cloud + resources grouped in such a way that, all + operations within one group are expected to be + performed atomically and in an order. + """ + operation_groups = proto.RepeatedField( + proto.MESSAGE, number=2, message="OperationGroup" + ) + + +class OperationGroup(proto.Message): + r"""Group of operations that need to be performed atomically. + + Attributes: + operations (Sequence[~.recommendation.Operation]): + List of operations across one or more + resources that belong to this group. Loosely + based on RFC6902 and should be performed in the + order they appear. + """ + operations = proto.RepeatedField(proto.MESSAGE, number=1, message="Operation") + + +class Operation(proto.Message): + r"""Contains an operation for a resource inspired by the JSON-PATCH + format with support for: + + - Custom filters for describing partial array patch. + - Extended path values for describing nested arrays. + - Custom fields for describing the resource for which the operation + is being described. + - Allows extension to custom operations not natively supported by + RFC6902. See https://tools.ietf.org/html/rfc6902 for details on + the original RFC. + + Attributes: + action (str): + Type of this operation. Contains one of + 'and', 'remove', 'replace', 'move', 'copy', + 'test' and custom operations. This field is + case-insensitive and always populated. + resource_type (str): + Type of GCP resource being modified/tested. + This field is always populated. Example: + cloudresourcemanager.googleapis.com/Project, + compute.googleapis.com/Instance + resource (str): + Contains the fully qualified resource name. + This field is always populated. ex: + //cloudresourcemanager.googleapis.com/projects/foo. + path (str): + Path to the target field being operated on. + If the operation is at the resource level, then + path should be "/". This field is always + populated. + source_resource (str): + Can be set with action 'copy' to copy resource configuration + across different resources of the same type. Example: A + resource clone can be done via action = 'copy', path = "/", + from = "/", source_resource = and resource_name = . This + field is empty for all other values of ``action``. + source_path (str): + Can be set with action 'copy' or 'move' to indicate the + source field within resource or source_resource, ignored if + provided for other operation types. + value (~.struct.Value): + Value for the ``path`` field. Set if action is + 'add'/'replace'/'test'. + path_filters (Sequence[~.recommendation.Operation.PathFiltersEntry]): + Set of filters to apply if ``path`` refers to array elements + or nested array elements in order to narrow down to a single + unique element that is being tested/modified. Note that this + is intended to be an exact match per filter. ``Example: { + "/versions/*/name" : "it-123" + "/versions/*/targetSize/percent": 20 }`` ``Example: { + "/bindings/*/role": "roles/admin" "/bindings/*/condition" : + null }`` ``Example: { "/bindings/*/role": "roles/admin" + "/bindings/*/members/*" : ["x@google.com", "y@google.com"] }`` + """ + + class PathFiltersEntry(proto.Message): + r""" + + Attributes: + key (str): + + value (~.struct.Value): + + """ + key = proto.Field(proto.STRING, number=1) + value = proto.Field(proto.MESSAGE, number=2, message=struct.Value) + + action = proto.Field(proto.STRING, number=1) + resource_type = proto.Field(proto.STRING, number=2) + resource = proto.Field(proto.STRING, number=3) + path = proto.Field(proto.STRING, number=4) + source_resource = proto.Field(proto.STRING, number=5) + source_path = proto.Field(proto.STRING, number=6) + value = proto.Field(proto.MESSAGE, number=7, message=struct.Value) + path_filters = proto.RepeatedField( + proto.MESSAGE, number=8, message=PathFiltersEntry + ) + + +class CostProjection(proto.Message): + r"""Contains metadata about how much money a recommendation can + save or incur. + + Attributes: + cost (~.money.Money): + An approximate projection on amount saved or + amount incurred. Negative cost units indicate + cost savings and positive cost units indicate + increase. See google.type.Money documentation + for positive/negative units. + duration (~.gp_duration.Duration): + Duration for which this cost applies. + """ + cost = proto.Field(proto.MESSAGE, number=1, message=money.Money) + duration = proto.Field(proto.MESSAGE, number=2, message=gp_duration.Duration) + + +class Impact(proto.Message): + r"""Contains the impact a recommendation can have for a given + category. + + Attributes: + category (~.recommendation.Impact.Category): + Category that is being targeted. + cost_projection (~.recommendation.CostProjection): + Use with CategoryType.COST + """ + + class Category(proto.Enum): + r"""The category of the impact.""" + CATEGORY_UNSPECIFIED = 0 + COST = 1 + SECURITY = 2 + PERFORMANCE = 3 + + category = proto.Field(proto.ENUM, number=1, enum=Category) + cost_projection = proto.Field(proto.MESSAGE, number=100, message=CostProjection) + + +class RecommendationStateInfo(proto.Message): + r"""Information for state. Contains state and metadata. + + Attributes: + state (~.recommendation.RecommendationStateInfo.State): + The state of the recommendation, Eg ACTIVE, + SUCCEEDED, FAILED. + state_metadata (Sequence[~.recommendation.RecommendationStateInfo.StateMetadataEntry]): + A map of metadata for the state, provided by + user or automations systems. + """ + + class State(proto.Enum): + r"""Represents Recommendation State""" + STATE_UNSPECIFIED = 0 + ACTIVE = 1 + CLAIMED = 6 + SUCCEEDED = 3 + FAILED = 4 + DISMISSED = 5 + + class StateMetadataEntry(proto.Message): + r""" + + Attributes: + key (str): + + value (str): + + """ + key = proto.Field(proto.STRING, number=1) + value = proto.Field(proto.STRING, number=2) + + state = proto.Field(proto.ENUM, number=1, enum=State) + state_metadata = proto.RepeatedField( + proto.MESSAGE, number=2, message=StateMetadataEntry + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/recommender/google/cloud/recommender_v1beta1/types/recommender_service.py b/recommender/google/cloud/recommender_v1beta1/types/recommender_service.py new file mode 100644 index 000000000000..af5aa187e26f --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/types/recommender_service.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +import proto # type: ignore + + +from google.cloud.recommender_v1beta1.types import recommendation + + +__protobuf__ = proto.module( + package="google.cloud.recommender.v1beta1", + manifest={ + "ListRecommendationsRequest", + "ListRecommendationsResponse", + "GetRecommendationRequest", + "MarkRecommendationClaimedRequest", + "MarkRecommendationSucceededRequest", + "MarkRecommendationFailedRequest", + }, +) + + +class ListRecommendationsRequest(proto.Message): + r"""Request for the ``ListRecommendations`` method. + + Attributes: + parent (str): + Required. The container resource on which to execute the + request. Acceptable formats: + + 1. + + "projects/[PROJECT_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER_ID]", + + LOCATION here refers to GCP Locations: + https://cloud.google.com/about/locations/ + page_size (int): + Optional. The maximum number of results to + return from this request. Non-positive values + are ignored. If not specified, the server will + determine the number of results to return. + page_token (str): + Optional. If present, retrieves the next batch of results + from the preceding call to this method. ``page_token`` must + be the value of ``next_page_token`` from the previous + response. The values of other method parameters must be + identical to those in the previous call. + filter (str): + Filter expression to restrict the recommendations returned. + Supported filter fields: state_info.state Eg: + \`state_info.state:"DISMISSED" or state_info.state:"FAILED". + """ + parent = proto.Field(proto.STRING, number=1) + page_size = proto.Field(proto.INT32, number=2) + page_token = proto.Field(proto.STRING, number=3) + filter = proto.Field(proto.STRING, number=5) + + +class ListRecommendationsResponse(proto.Message): + r"""Response to the ``ListRecommendations`` method. + + Attributes: + recommendations (Sequence[~.recommendation.Recommendation]): + The set of recommendations for the ``parent`` resource. + next_page_token (str): + A token that can be used to request the next + page of results. This field is empty if there + are no additional results. + """ + recommendations = proto.RepeatedField( + proto.MESSAGE, number=1, message=recommendation.Recommendation + ) + next_page_token = proto.Field(proto.STRING, number=2) + + +class GetRecommendationRequest(proto.Message): + r"""Request to the ``GetRecommendation`` method. + + Attributes: + name (str): + Name of the recommendation. + """ + name = proto.Field(proto.STRING, number=1) + + +class MarkRecommendationClaimedRequest(proto.Message): + r"""Request for the ``MarkRecommendationClaimed`` Method. + + Attributes: + name (str): + Name of the recommendation. + state_metadata (Sequence[~.recommender_service.MarkRecommendationClaimedRequest.StateMetadataEntry]): + State properties to include with this state. Overwrites any + existing ``state_metadata``. + etag (str): + Fingerprint of the Recommendation. Provides + optimistic locking. + """ + + class StateMetadataEntry(proto.Message): + r""" + + Attributes: + key (str): + + value (str): + + """ + key = proto.Field(proto.STRING, number=1) + value = proto.Field(proto.STRING, number=2) + + name = proto.Field(proto.STRING, number=1) + state_metadata = proto.RepeatedField( + proto.MESSAGE, number=2, message=StateMetadataEntry + ) + etag = proto.Field(proto.STRING, number=3) + + +class MarkRecommendationSucceededRequest(proto.Message): + r"""Request for the ``MarkRecommendationSucceeded`` Method. + + Attributes: + name (str): + Name of the recommendation. + state_metadata (Sequence[~.recommender_service.MarkRecommendationSucceededRequest.StateMetadataEntry]): + State properties to include with this state. Overwrites any + existing ``state_metadata``. + etag (str): + Fingerprint of the Recommendation. Provides + optimistic locking. + """ + + class StateMetadataEntry(proto.Message): + r""" + + Attributes: + key (str): + + value (str): + + """ + key = proto.Field(proto.STRING, number=1) + value = proto.Field(proto.STRING, number=2) + + name = proto.Field(proto.STRING, number=1) + state_metadata = proto.RepeatedField( + proto.MESSAGE, number=2, message=StateMetadataEntry + ) + etag = proto.Field(proto.STRING, number=3) + + +class MarkRecommendationFailedRequest(proto.Message): + r"""Request for the ``MarkRecommendationFailed`` Method. + + Attributes: + name (str): + Name of the recommendation. + state_metadata (Sequence[~.recommender_service.MarkRecommendationFailedRequest.StateMetadataEntry]): + State properties to include with this state. Overwrites any + existing ``state_metadata``. + etag (str): + Fingerprint of the Recommendation. Provides + optimistic locking. + """ + + class StateMetadataEntry(proto.Message): + r""" + + Attributes: + key (str): + + value (str): + + """ + key = proto.Field(proto.STRING, number=1) + value = proto.Field(proto.STRING, number=2) + + name = proto.Field(proto.STRING, number=1) + state_metadata = proto.RepeatedField( + proto.MESSAGE, number=2, message=StateMetadataEntry + ) + etag = proto.Field(proto.STRING, number=3) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/recommender/mypy.ini b/recommender/mypy.ini new file mode 100644 index 000000000000..f23e6b533aad --- /dev/null +++ b/recommender/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +python_version = 3.5 +namespace_packages = True diff --git a/recommender/noxfile.py b/recommender/noxfile.py new file mode 100644 index 000000000000..1f6797a2207f --- /dev/null +++ b/recommender/noxfile.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Generated by synthtool. DO NOT EDIT! + +from __future__ import absolute_import +import os +import shutil + +import nox + + +LOCAL_DEPS = (os.path.join("..", "api_core"), os.path.join("..", "core")) +BLACK_VERSION = "black==19.3b0" +BLACK_PATHS = ["docs", "google", "tests", "noxfile.py", "setup.py"] + +if os.path.exists("samples"): + BLACK_PATHS.append("samples") + + +@nox.session(python="3.7") +def lint(session): + """Run linters. + + Returns a failure if the linters find linting errors or sufficiently + serious code quality issues. + """ + session.install("flake8", BLACK_VERSION, *LOCAL_DEPS) + session.run("black", "--check", *BLACK_PATHS) + session.run("flake8", "google", "tests") + + +@nox.session(python="3.6") +def blacken(session): + """Run black. + + Format code to uniform standard. + + This currently uses Python 3.6 due to the automated Kokoro run of synthtool. + That run uses an image that doesn't have 3.6 installed. Before updating this + check the state of the `gcp_ubuntu_config` we use for that Kokoro run. + """ + session.install(BLACK_VERSION) + session.run("black", *BLACK_PATHS) + + +@nox.session(python="3.7") +def lint_setup_py(session): + """Verify that setup.py is valid (including RST check).""" + session.install("docutils", "pygments") + session.run("python", "setup.py", "check", "--restructuredtext", "--strict") + + +def default(session): + # Install all test dependencies, then install this package in-place. + session.install("mock", "pytest", "pytest-cov") + for local_dep in LOCAL_DEPS: + session.install("-e", local_dep) + session.install("-e", ".") + + # Run py.test against the unit tests. + session.run( + "py.test", + "--quiet", + "--cov=google.cloud", + "--cov=tests.unit", + "--cov-append", + "--cov-config=.coveragerc", + "--cov-report=", + "--cov-fail-under=0", + os.path.join("tests", "unit"), + *session.posargs, + ) + + +@nox.session(python=["3.5", "3.6", "3.7"]) +def unit(session): + """Run the unit test suite.""" + default(session) + + +@nox.session(python=["3.7"]) +def system(session): + """Run the system test suite.""" + system_test_path = os.path.join("tests", "system.py") + system_test_folder_path = os.path.join("tests", "system") + # Sanity check: Only run tests if the environment variable is set. + if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""): + session.skip("Credentials must be set via environment variable") + + system_test_exists = os.path.exists(system_test_path) + system_test_folder_exists = os.path.exists(system_test_folder_path) + # Sanity check: only run tests if found. + if not system_test_exists and not system_test_folder_exists: + session.skip("System tests were not found") + + # Use pre-release gRPC for system tests. + session.install("--pre", "grpcio") + + # Install all test dependencies, then install this package into the + # virtualenv's dist-packages. + session.install("mock", "pytest") + for local_dep in LOCAL_DEPS: + session.install("-e", local_dep) + session.install("-e", "../test_utils/") + session.install("-e", ".") + + # Run py.test against the system tests. + if system_test_exists: + session.run("py.test", "--quiet", system_test_path, *session.posargs) + if system_test_folder_exists: + session.run("py.test", "--quiet", system_test_folder_path, *session.posargs) + + +@nox.session(python="3.7") +def cover(session): + """Run the final coverage report. + + This outputs the coverage report aggregating coverage from the unit + test runs (not system test runs), and then erases coverage data. + """ + session.install("coverage", "pytest-cov") + session.run("coverage", "report", "--show-missing", "--fail-under=100") + + session.run("coverage", "erase") + + +@nox.session(python="3.7") +def docs(session): + """Build the docs for this library.""" + + session.install("-e", ".") + session.install("sphinx", "alabaster", "recommonmark") + + shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True) + session.run( + "sphinx-build", + "-W", # warnings as errors + "-T", # show full traceback on exception + "-N", # no colors + "-b", + "html", + "-d", + os.path.join("docs", "_build", "doctrees", ""), + os.path.join("docs", ""), + os.path.join("docs", "_build", "html", ""), + ) diff --git a/recommender/setup.cfg b/recommender/setup.cfg new file mode 100644 index 000000000000..3bd555500e37 --- /dev/null +++ b/recommender/setup.cfg @@ -0,0 +1,3 @@ +# Generated by synthtool. DO NOT EDIT! +[bdist_wheel] +universal = 1 diff --git a/recommender/setup.py b/recommender/setup.py new file mode 100644 index 000000000000..dd367cb7b763 --- /dev/null +++ b/recommender/setup.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +import setuptools # type: ignore + + +setuptools.setup( + name="google-cloud-recommender", + version="0.0.1", + packages=setuptools.PEP420PackageFinder.find(), + namespace_packages=("google", "google.cloud"), + platforms="Posix; MacOS X; Windows", + include_package_data=True, + install_requires=( + "google-api-core >= 1.8.0, < 2.0.0dev", + "googleapis-common-protos >= 1.5.8", + "grpcio >= 1.10.0", + "proto-plus >= 0.4.0", + ), + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Topic :: Internet", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + zip_safe=False, +) diff --git a/recommender/synth.metadata b/recommender/synth.metadata new file mode 100644 index 000000000000..f63a3117c94b --- /dev/null +++ b/recommender/synth.metadata @@ -0,0 +1,31 @@ +{ + "updateTime": "2019-09-20T18:07:54.249961Z", + "sources": [ + { + "git": { + "name": "googleapis", + "remote": "https://github.com/googleapis/googleapis.git", + "sha": "2e02174cad304dac67a40e1f63885964c4db91b2", + "internalRef": "270249401" + } + }, + { + "template": { + "name": "python_library", + "origin": "synthtool.gcp", + "version": "2019.5.2" + } + } + ], + "destinations": [ + { + "client": { + "source": "googleapis", + "apiName": "recommender", + "apiVersion": "v1beta1", + "language": "python", + "generator": "gapic-generator-python" + } + } + ] +} \ No newline at end of file diff --git a/recommender/synth.py b/recommender/synth.py new file mode 100644 index 000000000000..9795678d6628 --- /dev/null +++ b/recommender/synth.py @@ -0,0 +1,88 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This script is used to synthesize generated parts of this library.""" +import re + +import synthtool as s +from synthtool import gcp + +gapic = gcp.GAPICMicrogenerator() +versions = ["v1beta1"] +common = gcp.CommonTemplates() + + +# ---------------------------------------------------------------------------- +# Generate Cloud Recommender +# ---------------------------------------------------------------------------- +for version in versions: + library = gapic.py_library( + "recommender", version, proto_path=f"google/cloud/recommender/{version}", + ) + s.move(library, excludes="noxfile.py") + +# https://github.com/googleapis/gapic-generator-python/pull/175 +s.replace("google/cloud/**/*.py", +""", +(\s+)\) ->""", +""" +\g<1>) ->""") + +# Fix lint errors about unused variables in tests +# TODO: Add GitHub issue here +s.replace("tests/**/test_recommender.py", +"""(\s+)call\.return_value = recommender_service\.ListRecommendationsResponse\(\) +(\s+)response = client\.list_recommendations\(request\)""", +"""\g<1>call.return_value = recommender_service.ListRecommendationsResponse() +\g<2>client.list_recommendations(request)""") + +s.replace("tests/**/test_recommender.py", +"""(\s+)call\.return_value = recommendation\.Recommendation\(\) +(\s+)response = client\.get_recommendation\(request\)""", +"""\g<1>call.return_value = recommendation.Recommendation() +\g<2>client.get_recomemndation(request)""") + + +s.replace("tests/**/test_recommender.py", +"""(\s+)with pytest\.raises\(ValueError\): +(\s+)client = Recommender\( +(\s+)credentials=credentials\.AnonymousCredentials\(\), +(\s+)transport=transport, +(\s+)\) +""", +"""\g<1>with pytest.raises(ValueError): +\g<2>Recommender( +\g<3>credentials=credentials.AnonymousCredentials(), +\g<4>transport=transport +\g<5>) +""") + +s.replace("tests/**/test_recommender.py", +"""(\s+)client = Recommender\(\) +(\s+)adc\.assert_called_once_with\(""", +"""\g<1>Recommender() +\g<2>adc.assert_called_once_with(""") + +# Fix formatting in docstring +s.replace("google/cloud/**/recommendation.py", +"""(Example:\s+\{.+?\})""", +"""``\g<1>``""", flags=re.DOTALL) + +# ---------------------------------------------------------------------------- +# Add templated files +# ---------------------------------------------------------------------------- +templated_files = common.py_library(unit_cov_level=97, cov_level=100) +s.move(templated_files, excludes=["noxfile.py"]) + +s.shell.run(["nox", "-s", "blacken"], hide_output=False) \ No newline at end of file diff --git a/recommender/tests/unit/recommender_v1beta1/test_recommender.py b/recommender/tests/unit/recommender_v1beta1/test_recommender.py new file mode 100644 index 000000000000..a3da3f99be43 --- /dev/null +++ b/recommender/tests/unit/recommender_v1beta1/test_recommender.py @@ -0,0 +1,345 @@ +# -*- coding: utf-8 -*- +from unittest import mock + +import grpc + +import pytest + +from google import auth +from google.auth import credentials +from google.cloud.recommender_v1beta1.services.recommender import Recommender +from google.cloud.recommender_v1beta1.services.recommender import pagers +from google.cloud.recommender_v1beta1.services.recommender import transports +from google.cloud.recommender_v1beta1.types import recommendation +from google.cloud.recommender_v1beta1.types import recommender_service + + +def test_list_recommendations(transport: str = "grpc"): + client = Recommender( + credentials=credentials.AnonymousCredentials(), transport=transport + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = recommender_service.ListRecommendationsRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.list_recommendations), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = recommender_service.ListRecommendationsResponse( + next_page_token="next_page_token_value" + ) + response = client.list_recommendations(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, pagers.ListRecommendationsPager) + assert response.next_page_token == "next_page_token_value" + + +def test_list_recommendations_field_headers(): + client = Recommender(credentials=credentials.AnonymousCredentials()) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = recommender_service.ListRecommendationsRequest(parent="parent/value") + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.list_recommendations), "__call__" + ) as call: + call.return_value = recommender_service.ListRecommendationsResponse() + client.list_recommendations(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "parent=parent/value") in kw["metadata"] + + +def test_list_recommendations_pager(): + client = Recommender(credentials=credentials.AnonymousCredentials) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.list_recommendations), "__call__" + ) as call: + # Set the response to a series of pages. + call.side_effect = ( + recommender_service.ListRecommendationsResponse( + recommendations=[ + recommendation.Recommendation(), + recommendation.Recommendation(), + recommendation.Recommendation(), + ], + next_page_token="abc", + ), + recommender_service.ListRecommendationsResponse( + recommendations=[], next_page_token="def" + ), + recommender_service.ListRecommendationsResponse( + recommendations=[recommendation.Recommendation()], next_page_token="ghi" + ), + recommender_service.ListRecommendationsResponse( + recommendations=[ + recommendation.Recommendation(), + recommendation.Recommendation(), + ] + ), + RuntimeError, + ) + results = [i for i in client.list_recommendations(request={})] + assert len(results) == 6 + assert all([isinstance(i, recommendation.Recommendation) for i in results]) + + +def test_get_recommendation(transport: str = "grpc"): + client = Recommender( + credentials=credentials.AnonymousCredentials(), transport=transport + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = recommender_service.GetRecommendationRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.get_recommendation), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = recommendation.Recommendation( + name="name_value", + description="description_value", + recommender_subtype="recommender_subtype_value", + etag="etag_value", + ) + response = client.get_recommendation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, recommendation.Recommendation) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.recommender_subtype == "recommender_subtype_value" + assert response.etag == "etag_value" + + +def test_get_recommendation_field_headers(): + client = Recommender(credentials=credentials.AnonymousCredentials()) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = recommender_service.GetRecommendationRequest(name="name/value") + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.get_recommendation), "__call__" + ) as call: + call.return_value = recommendation.Recommendation() + client.get_recomemndation(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ("x-goog-request-params", "name=name/value") in kw["metadata"] + + +def test_mark_recommendation_claimed(transport: str = "grpc"): + client = Recommender( + credentials=credentials.AnonymousCredentials(), transport=transport + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = recommender_service.MarkRecommendationClaimedRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.mark_recommendation_claimed), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = recommendation.Recommendation( + name="name_value", + description="description_value", + recommender_subtype="recommender_subtype_value", + etag="etag_value", + ) + response = client.mark_recommendation_claimed(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, recommendation.Recommendation) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.recommender_subtype == "recommender_subtype_value" + assert response.etag == "etag_value" + + +def test_mark_recommendation_succeeded(transport: str = "grpc"): + client = Recommender( + credentials=credentials.AnonymousCredentials(), transport=transport + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = recommender_service.MarkRecommendationSucceededRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.mark_recommendation_succeeded), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = recommendation.Recommendation( + name="name_value", + description="description_value", + recommender_subtype="recommender_subtype_value", + etag="etag_value", + ) + response = client.mark_recommendation_succeeded(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, recommendation.Recommendation) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.recommender_subtype == "recommender_subtype_value" + assert response.etag == "etag_value" + + +def test_mark_recommendation_failed(transport: str = "grpc"): + client = Recommender( + credentials=credentials.AnonymousCredentials(), transport=transport + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = recommender_service.MarkRecommendationFailedRequest() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client._transport.mark_recommendation_failed), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = recommendation.Recommendation( + name="name_value", + description="description_value", + recommender_subtype="recommender_subtype_value", + etag="etag_value", + ) + response = client.mark_recommendation_failed(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, recommendation.Recommendation) + assert response.name == "name_value" + assert response.description == "description_value" + assert response.recommender_subtype == "recommender_subtype_value" + assert response.etag == "etag_value" + + +def test_credentials_transport_error(): + # It is an error to provide credentials and a transport instance. + transport = transports.RecommenderGrpcTransport( + credentials=credentials.AnonymousCredentials() + ) + with pytest.raises(ValueError): + Recommender(credentials=credentials.AnonymousCredentials(), transport=transport) + + +def test_transport_instance(): + # A client may be instantiated with a custom transport instance. + transport = transports.RecommenderGrpcTransport( + credentials=credentials.AnonymousCredentials() + ) + client = Recommender(transport=transport) + assert client._transport is transport + + +def test_transport_grpc_default(): + # A client should use the gRPC transport by default. + client = Recommender(credentials=credentials.AnonymousCredentials()) + assert isinstance(client._transport, transports.RecommenderGrpcTransport) + + +def test_recommender_base_transport(): + # Instantiate the base transport. + transport = transports.RecommenderTransport( + credentials=credentials.AnonymousCredentials() + ) + + # Every method on the transport should just blindly + # raise NotImplementedError. + methods = ( + "list_recommendations", + "get_recommendation", + "mark_recommendation_claimed", + "mark_recommendation_succeeded", + "mark_recommendation_failed", + ) + for method in methods: + with pytest.raises(NotImplementedError): + getattr(transport, method)(request=object()) + + +def test_recommender_auth_adc(): + # If no credentials are provided, we should use ADC credentials. + with mock.patch.object(auth, "default") as adc: + adc.return_value = (credentials.AnonymousCredentials(), None) + Recommender() + adc.assert_called_once_with( + scopes=("https://www.googleapis.com/auth/cloud-platform",) + ) + + +def test_recommender_host_no_port(): + client = Recommender( + credentials=credentials.AnonymousCredentials(), + host="recommender.googleapis.com", + transport="grpc", + ) + assert client._transport._host == "recommender.googleapis.com:443" + + +def test_recommender_host_with_port(): + client = Recommender( + credentials=credentials.AnonymousCredentials(), + host="recommender.googleapis.com:8000", + transport="grpc", + ) + assert client._transport._host == "recommender.googleapis.com:8000" + + +def test_recommender_grpc_transport_channel(): + channel = grpc.insecure_channel("http://localhost/") + transport = transports.RecommenderGrpcTransport(channel=channel) + assert transport.grpc_channel is channel From 482262114d1e80de299e9f7235faa9e02474df5c Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 13:54:37 -0700 Subject: [PATCH 02/14] Add smoke test. --- recommender/tests/system.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 recommender/tests/system.py diff --git a/recommender/tests/system.py b/recommender/tests/system.py new file mode 100644 index 000000000000..5a5196b52f1b --- /dev/null +++ b/recommender/tests/system.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import unittest + +from google.cloud.recommender_v1beta1.services.recommender import Recommender +from google.cloud.recommender_v1beta1 import ListRecommendationsRequest + + +class TestRecommender(unittest.TestCase): + def test_list_recommendations(self): + client = Recommender() + PROJECT_ID = os.environ.get("PROJECT_ID") + parent = f"projects/{PROJECT_ID}/locations/global" + request = ListRecommendationsRequest(parent=parent) + client.list_recommendations(request=request) \ No newline at end of file From 376a4a346661c18e34fc9241d37740577e67910c Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 14:00:50 -0700 Subject: [PATCH 03/14] Add kokoro configs in GitHub. --- .kokoro/continuous/recommender.cfg | 7 +++++++ .kokoro/docs/recommender.cfg | 7 +++++++ .kokoro/presubmit/recommender.cfg | 7 +++++++ .kokoro/release/recommender.cfg | 7 +++++++ 4 files changed, 28 insertions(+) create mode 100644 .kokoro/continuous/recommender.cfg create mode 100644 .kokoro/docs/recommender.cfg create mode 100644 .kokoro/presubmit/recommender.cfg create mode 100644 .kokoro/release/recommender.cfg diff --git a/.kokoro/continuous/recommender.cfg b/.kokoro/continuous/recommender.cfg new file mode 100644 index 000000000000..7d65909e6343 --- /dev/null +++ b/.kokoro/continuous/recommender.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Tell the trampoline which build file to use. +env_vars: { + key: "PACKAGE" + value: "recommender" +} diff --git a/.kokoro/docs/recommender.cfg b/.kokoro/docs/recommender.cfg new file mode 100644 index 000000000000..7d65909e6343 --- /dev/null +++ b/.kokoro/docs/recommender.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Tell the trampoline which build file to use. +env_vars: { + key: "PACKAGE" + value: "recommender" +} diff --git a/.kokoro/presubmit/recommender.cfg b/.kokoro/presubmit/recommender.cfg new file mode 100644 index 000000000000..7d65909e6343 --- /dev/null +++ b/.kokoro/presubmit/recommender.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Tell the trampoline which build file to use. +env_vars: { + key: "PACKAGE" + value: "recommender" +} diff --git a/.kokoro/release/recommender.cfg b/.kokoro/release/recommender.cfg new file mode 100644 index 000000000000..7d65909e6343 --- /dev/null +++ b/.kokoro/release/recommender.cfg @@ -0,0 +1,7 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Tell the trampoline which build file to use. +env_vars: { + key: "PACKAGE" + value: "recommender" +} From 48fa7d08eabb2a2114c6b3aed5fcfb7d3880bee1 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 15:47:21 -0700 Subject: [PATCH 04/14] Generate with gapic generator. --- recommender/CHANGELOG.md | 5 - recommender/LICENSE | 201 +++ recommender/README.rst | 41 +- recommender/docs/README.rst | 1 - recommender/docs/changelog.md | 1 - recommender/docs/conf.py | 6 +- recommender/docs/gapic/v1beta1/api.rst | 6 + recommender/docs/gapic/v1beta1/types.rst | 5 + recommender/docs/index.rst | 88 +- .../docs/recommender_v1beta1/services.rst | 8 - .../docs/recommender_v1beta1/types.rst | 10 - recommender/google/__init__.py | 24 + recommender/google/cloud/__init__.py | 24 + recommender/google/cloud/recommender.py | 25 + .../google/cloud/recommender/__init__.py | 47 - recommender/google/cloud/recommender/py.typed | 2 - .../cloud/recommender_v1beta1/__init__.py | 57 +- .../recommender_v1beta1/gapic/__init__.py | 0 .../cloud/recommender_v1beta1/gapic/enums.py | 88 ++ .../gapic/recommender_client.py | 670 ++++++++++ .../gapic/recommender_client_config.py | 48 + .../gapic/transports/__init__.py | 0 .../transports/recommender_grpc_transport.py | 202 +++ .../recommender_v1beta1/proto/__init__.py | 0 .../proto/recommendation_pb2.py | 1119 +++++++++++++++++ .../proto/recommendation_pb2_grpc.py | 2 + .../proto/recommender_service_pb2.py | 924 ++++++++++++++ .../proto/recommender_service_pb2_grpc.py | 155 +++ .../google/cloud/recommender_v1beta1/py.typed | 2 - .../recommender_v1beta1/services/__init__.py | 1 - .../services/recommender/__init__.py | 4 - .../services/recommender/client.py | 395 ------ .../services/recommender/pagers.py | 67 - .../recommender/transports/__init__.py | 14 - .../services/recommender/transports/base.py | 91 -- .../services/recommender/transports/grpc.py | 258 ---- .../google/cloud/recommender_v1beta1/types.py | 48 + .../types/recommendation.py | 275 ---- .../types/recommender_service.py | 183 --- recommender/nox.py | 55 + recommender/noxfile.py | 4 +- recommender/setup.py | 82 +- recommender/synth.metadata | 16 +- recommender/synth.py | 55 +- recommender/tests/system.py | 6 +- .../test_recommender_client_v1beta1.py | 324 +++++ .../recommender_v1beta1/test_recommender.py | 345 ----- 47 files changed, 4133 insertions(+), 1851 deletions(-) delete mode 100644 recommender/CHANGELOG.md create mode 100644 recommender/LICENSE delete mode 120000 recommender/docs/README.rst delete mode 120000 recommender/docs/changelog.md create mode 100644 recommender/docs/gapic/v1beta1/api.rst create mode 100644 recommender/docs/gapic/v1beta1/types.rst delete mode 100644 recommender/docs/recommender_v1beta1/services.rst delete mode 100644 recommender/docs/recommender_v1beta1/types.rst create mode 100644 recommender/google/__init__.py create mode 100644 recommender/google/cloud/__init__.py create mode 100644 recommender/google/cloud/recommender.py delete mode 100644 recommender/google/cloud/recommender/__init__.py delete mode 100644 recommender/google/cloud/recommender/py.typed create mode 100644 recommender/google/cloud/recommender_v1beta1/gapic/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/gapic/enums.py create mode 100644 recommender/google/cloud/recommender_v1beta1/gapic/recommender_client.py create mode 100644 recommender/google/cloud/recommender_v1beta1/gapic/recommender_client_config.py create mode 100644 recommender/google/cloud/recommender_v1beta1/gapic/transports/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/gapic/transports/recommender_grpc_transport.py create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/__init__.py create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2.py create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2_grpc.py create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2.py create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2_grpc.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/py.typed delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/__init__.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/client.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py create mode 100644 recommender/google/cloud/recommender_v1beta1/types.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/types/recommendation.py delete mode 100644 recommender/google/cloud/recommender_v1beta1/types/recommender_service.py create mode 100644 recommender/nox.py create mode 100644 recommender/tests/unit/gapic/v1beta1/test_recommender_client_v1beta1.py delete mode 100644 recommender/tests/unit/recommender_v1beta1/test_recommender.py diff --git a/recommender/CHANGELOG.md b/recommender/CHANGELOG.md deleted file mode 100644 index 7459c5dea295..000000000000 --- a/recommender/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -[PyPI History][1] - -[1]: https://pypi.org/project/google-cloud-recommender/#history \ No newline at end of file diff --git a/recommender/LICENSE b/recommender/LICENSE new file mode 100644 index 000000000000..a8ee855de2aa --- /dev/null +++ b/recommender/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/recommender/README.rst b/recommender/README.rst index 225d86d9e514..306ef7feaca4 100644 --- a/recommender/README.rst +++ b/recommender/README.rst @@ -1,20 +1,15 @@ -Python Client for Cloud Recommender API -============================================= +Python Client for Recommender API (`Alpha`_) +============================================ -|alpha| |pypi| |versions| +`Recommender API`_: - `Client Library Documentation`_ - `Product Documentation`_ -.. |alpha| image:: https://img.shields.io/badge/support-alpha-orange.svg - :target: https://github.com/googleapis/google-cloud-python/blob/master/README.rst#alpha-support -.. |pypi| image:: https://img.shields.io/pypi/v/google-cloud-recommender.svg - :target: https://pypi.org/project/google-cloud-recommender/ -.. |versions| image:: https://img.shields.io/pypi/pyversions/google-cloud-recommender.svg - :target: https://pypi.org/project/google-cloud-recommender/ -.. _Cloud Recommender API: https://cloud.google.com/recommendations-ai/ -.. _Client Library Documentation: https://googleapis.dev/python/recommender/latest -.. _Product Documentation: https://cloud.google.com/recommendations-ai/docs/ +.. _Alpha: https://github.com/googleapis/google-cloud-python/blob/master/README.rst +.. _Recommender API: https://cloud.google.com/recommender +.. _Client Library Documentation: https://googleapis.github.io/google-cloud-python/latest/recommender/usage.html +.. _Product Documentation: https://cloud.google.com/recommender Quick Start ----------- @@ -23,13 +18,13 @@ In order to use this library, you first need to go through the following steps: 1. `Select or create a Cloud Platform project.`_ 2. `Enable billing for your project.`_ -3. `Enable the Cloud Recommender API.`_ +3. `Enable the Recommender API.`_ 4. `Setup Authentication.`_ .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project -.. _Enable the Cloud Recommender API.: https://cloud.google.com/Recommender -.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html +.. _Enable the Recommender API.: https://cloud.google.com/recommender +.. _Setup Authentication.: https://googleapis.github.io/google-cloud-python/latest/core/auth.html Installation ~~~~~~~~~~~~ @@ -45,11 +40,6 @@ dependencies. .. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ -Supported Python Versions -^^^^^^^^^^^^^^^^^^^^^^^^^ -Python >= 3.5 - - Mac/Linux ^^^^^^^^^ @@ -74,7 +64,12 @@ Windows Next Steps ~~~~~~~~~~ -- Read the `Client Library Documentation`_ for Cloud Recommender API +- Read the `Client Library Documentation`_ for Recommender API API to see other available methods on the client. -- Read the `Product documentation`_ to learn - more about the product and see How-to Guides. \ No newline at end of file +- Read the `Recommender API Product documentation`_ to learn + more about the product and see How-to Guides. +- View this `repository’s main README`_ to see the full list of Cloud + APIs that we cover. + +.. _Recommender API Product documentation: https://cloud.google.com/recommender +.. _repository’s main README: https://github.com/googleapis/google-cloud-python/blob/master/README.rst \ No newline at end of file diff --git a/recommender/docs/README.rst b/recommender/docs/README.rst deleted file mode 120000 index 89a0106941ff..000000000000 --- a/recommender/docs/README.rst +++ /dev/null @@ -1 +0,0 @@ -../README.rst \ No newline at end of file diff --git a/recommender/docs/changelog.md b/recommender/docs/changelog.md deleted file mode 120000 index 04c99a55caae..000000000000 --- a/recommender/docs/changelog.md +++ /dev/null @@ -1 +0,0 @@ -../CHANGELOG.md \ No newline at end of file diff --git a/recommender/docs/conf.py b/recommender/docs/conf.py index 9cd1b152279a..4f8382a64bd6 100644 --- a/recommender/docs/conf.py +++ b/recommender/docs/conf.py @@ -318,7 +318,7 @@ u"google-cloud-recommender Documentation", author, "google-cloud-recommender", - "GAPIC library for the {metadata.shortName} v2 service", + "GAPIC library for the {metadata.shortName} v1beta1 service", "APIs", ) ] @@ -339,10 +339,14 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("http://python.readthedocs.org/en/latest/", None), + "gax": ("https://gax-python.readthedocs.org/en/latest/", None), "google-auth": ("https://google-auth.readthedocs.io/en/stable", None), + "google-gax": ("https://gax-python.readthedocs.io/en/latest/", None), "google.api_core": ("https://googleapis.dev/python/google-api-core/latest", None), "grpc": ("https://grpc.io/grpc/python/", None), "requests": ("https://2.python-requests.org/en/master/", None), + "fastavro": ("https://fastavro.readthedocs.io/en/stable/", None), + "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), } diff --git a/recommender/docs/gapic/v1beta1/api.rst b/recommender/docs/gapic/v1beta1/api.rst new file mode 100644 index 000000000000..d9458d258e2a --- /dev/null +++ b/recommender/docs/gapic/v1beta1/api.rst @@ -0,0 +1,6 @@ +Client for Recommender API +========================== + +.. automodule:: google.cloud.recommender_v1beta1 + :members: + :inherited-members: \ No newline at end of file diff --git a/recommender/docs/gapic/v1beta1/types.rst b/recommender/docs/gapic/v1beta1/types.rst new file mode 100644 index 000000000000..3771da42e95f --- /dev/null +++ b/recommender/docs/gapic/v1beta1/types.rst @@ -0,0 +1,5 @@ +Types for Recommender API Client +================================ + +.. automodule:: google.cloud.recommender_v1beta1.types + :members: \ No newline at end of file diff --git a/recommender/docs/index.rst b/recommender/docs/index.rst index a16e9b57f67f..1405c9ab2208 100644 --- a/recommender/docs/index.rst +++ b/recommender/docs/index.rst @@ -1,19 +1,83 @@ -.. include:: README.rst +Python Client for Recommender API (`Alpha`_) +============================================ -Api Reference -------------- -.. toctree:: - :maxdepth: 2 +`Recommender API`_: + +- `Client Library Documentation`_ +- `Product Documentation`_ + +.. _Alpha: https://github.com/googleapis/google-cloud-python/blob/master/README.rst +.. _Recommender API: https://cloud.google.com/recommender +.. _Client Library Documentation: https://googleapis.github.io/google-cloud-python/latest/recommender/usage.html +.. _Product Documentation: https://cloud.google.com/recommender + +Quick Start +----------- + +In order to use this library, you first need to go through the following steps: + +1. `Select or create a Cloud Platform project.`_ +2. `Enable billing for your project.`_ +3. `Enable the Recommender API.`_ +4. `Setup Authentication.`_ + +.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project +.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project +.. _Enable the Recommender API.: https://cloud.google.com/recommender +.. _Setup Authentication.: https://googleapis.github.io/google-cloud-python/latest/core/auth.html + +Installation +~~~~~~~~~~~~ + +Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to +create isolated Python environments. The basic problem it addresses is one of +dependencies and versions, and indirectly permissions. + +With `virtualenv`_, it's possible to install this library without needing system +install permissions, and without clashing with the installed system +dependencies. - recommender_v1beta1/services - recommender_v1beta1/types +.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ -Changelog ---------- -For a list of all ``google-cloud-recommender`` releases: +Mac/Linux +^^^^^^^^^ +.. code-block:: console + + pip install virtualenv + virtualenv + source /bin/activate + /bin/pip install google-cloud-recommender + + +Windows +^^^^^^^ + +.. code-block:: console + + pip install virtualenv + virtualenv + \Scripts\activate + \Scripts\pip.exe install google-cloud-recommender + +Next Steps +~~~~~~~~~~ + +- Read the `Client Library Documentation`_ for Recommender API + API to see other available methods on the client. +- Read the `Recommender API Product documentation`_ to learn + more about the product and see How-to Guides. +- View this `repository’s main README`_ to see the full list of Cloud + APIs that we cover. + +.. _Recommender API Product documentation: https://cloud.google.com/recommender +.. _repository’s main README: https://github.com/googleapis/google-cloud-python/blob/master/README.rst + +Api Reference +------------- .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - changelog \ No newline at end of file + gapic/v1beta1/api + gapic/v1beta1/types \ No newline at end of file diff --git a/recommender/docs/recommender_v1beta1/services.rst b/recommender/docs/recommender_v1beta1/services.rst deleted file mode 100644 index e413521826f1..000000000000 --- a/recommender/docs/recommender_v1beta1/services.rst +++ /dev/null @@ -1,8 +0,0 @@ -Client for Cloud Recommender API -=============================================== - -.. automodule:: google.cloud.recommender_v1beta1.services.recommender.client - :members: - -.. automodule:: google.cloud.recommender_v1beta1.services.recommender.pagers - :members: \ No newline at end of file diff --git a/recommender/docs/recommender_v1beta1/types.rst b/recommender/docs/recommender_v1beta1/types.rst deleted file mode 100644 index 1bc5dca6500c..000000000000 --- a/recommender/docs/recommender_v1beta1/types.rst +++ /dev/null @@ -1,10 +0,0 @@ -Types for Cloud Recommender API -=============================================== - -.. automodule:: google.cloud.recommender_v1beta1.types.recommendation - :members: - :undoc-members: - -.. automodule:: google.cloud.recommender_v1beta1.types.recommender_service - :members: - :undoc-members: \ No newline at end of file diff --git a/recommender/google/__init__.py b/recommender/google/__init__.py new file mode 100644 index 000000000000..8fcc60e2b9c6 --- /dev/null +++ b/recommender/google/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/recommender/google/cloud/__init__.py b/recommender/google/cloud/__init__.py new file mode 100644 index 000000000000..8fcc60e2b9c6 --- /dev/null +++ b/recommender/google/cloud/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +try: + import pkg_resources + + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/recommender/google/cloud/recommender.py b/recommender/google/cloud/recommender.py new file mode 100644 index 000000000000..3caae5792568 --- /dev/null +++ b/recommender/google/cloud/recommender.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from __future__ import absolute_import + +from google.cloud.recommender_v1beta1 import RecommenderClient +from google.cloud.recommender_v1beta1 import enums +from google.cloud.recommender_v1beta1 import types + + +__all__ = ("enums", "types", "RecommenderClient") diff --git a/recommender/google/cloud/recommender/__init__.py b/recommender/google/cloud/recommender/__init__.py deleted file mode 100644 index 35baf54bdf29..000000000000 --- a/recommender/google/cloud/recommender/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -from google.cloud.recommender_v1beta1.services.recommender.client import Recommender -from google.cloud.recommender_v1beta1.types.recommendation import CostProjection -from google.cloud.recommender_v1beta1.types.recommendation import Impact -from google.cloud.recommender_v1beta1.types.recommendation import Operation -from google.cloud.recommender_v1beta1.types.recommendation import OperationGroup -from google.cloud.recommender_v1beta1.types.recommendation import Recommendation -from google.cloud.recommender_v1beta1.types.recommendation import RecommendationContent -from google.cloud.recommender_v1beta1.types.recommendation import ( - RecommendationStateInfo, -) -from google.cloud.recommender_v1beta1.types.recommender_service import ( - GetRecommendationRequest, -) -from google.cloud.recommender_v1beta1.types.recommender_service import ( - ListRecommendationsRequest, -) -from google.cloud.recommender_v1beta1.types.recommender_service import ( - ListRecommendationsResponse, -) -from google.cloud.recommender_v1beta1.types.recommender_service import ( - MarkRecommendationClaimedRequest, -) -from google.cloud.recommender_v1beta1.types.recommender_service import ( - MarkRecommendationFailedRequest, -) -from google.cloud.recommender_v1beta1.types.recommender_service import ( - MarkRecommendationSucceededRequest, -) - - -__all__ = ( - "Recommender", - "CostProjection", - "Impact", - "Operation", - "OperationGroup", - "Recommendation", - "RecommendationContent", - "RecommendationStateInfo", - "GetRecommendationRequest", - "ListRecommendationsRequest", - "ListRecommendationsResponse", - "MarkRecommendationClaimedRequest", - "MarkRecommendationFailedRequest", - "MarkRecommendationSucceededRequest", -) diff --git a/recommender/google/cloud/recommender/py.typed b/recommender/google/cloud/recommender/py.typed deleted file mode 100644 index f9105be894e2..000000000000 --- a/recommender/google/cloud/recommender/py.typed +++ /dev/null @@ -1,2 +0,0 @@ -# Marker file for PEP 561. -# The google-cloud-recommender package uses inline types. diff --git a/recommender/google/cloud/recommender_v1beta1/__init__.py b/recommender/google/cloud/recommender_v1beta1/__init__.py index cb8f79f143c4..2ea08cfa4d18 100644 --- a/recommender/google/cloud/recommender_v1beta1/__init__.py +++ b/recommender/google/cloud/recommender_v1beta1/__init__.py @@ -1,33 +1,30 @@ # -*- coding: utf-8 -*- -from .services.recommender import Recommender -from .types.recommendation import CostProjection -from .types.recommendation import Impact -from .types.recommendation import Operation -from .types.recommendation import OperationGroup -from .types.recommendation import Recommendation -from .types.recommendation import RecommendationContent -from .types.recommendation import RecommendationStateInfo -from .types.recommender_service import GetRecommendationRequest -from .types.recommender_service import ListRecommendationsRequest -from .types.recommender_service import ListRecommendationsResponse -from .types.recommender_service import MarkRecommendationClaimedRequest -from .types.recommender_service import MarkRecommendationFailedRequest -from .types.recommender_service import MarkRecommendationSucceededRequest +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. -__all__ = ( - "CostProjection", - "GetRecommendationRequest", - "Impact", - "ListRecommendationsRequest", - "ListRecommendationsResponse", - "MarkRecommendationClaimedRequest", - "MarkRecommendationFailedRequest", - "MarkRecommendationSucceededRequest", - "Operation", - "OperationGroup", - "Recommendation", - "RecommendationContent", - "RecommendationStateInfo", - "Recommender", -) +from __future__ import absolute_import + +from google.cloud.recommender_v1beta1 import types +from google.cloud.recommender_v1beta1.gapic import enums +from google.cloud.recommender_v1beta1.gapic import recommender_client + + +class RecommenderClient(recommender_client.RecommenderClient): + __doc__ = recommender_client.RecommenderClient.__doc__ + enums = enums + + +__all__ = ("enums", "types", "RecommenderClient") diff --git a/recommender/google/cloud/recommender_v1beta1/gapic/__init__.py b/recommender/google/cloud/recommender_v1beta1/gapic/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/recommender/google/cloud/recommender_v1beta1/gapic/enums.py b/recommender/google/cloud/recommender_v1beta1/gapic/enums.py new file mode 100644 index 000000000000..5d7fbb6b7a31 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/gapic/enums.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Wrappers for protocol buffer enum types.""" + +import enum + + +class NullValue(enum.IntEnum): + """ + ``NullValue`` is a singleton enumeration to represent the null value for + the ``Value`` type union. + + The JSON representation for ``NullValue`` is JSON ``null``. + + Attributes: + NULL_VALUE (int): Null value. + """ + + NULL_VALUE = 0 + + +class Impact(object): + class Category(enum.IntEnum): + """ + The category of the impact. + + Attributes: + CATEGORY_UNSPECIFIED (int): Default unspecified category. Don't use directly. + COST (int): Indicates a potential increase or decrease in cost. + SECURITY (int): Indicates a potential increase or decrease in security. + PERFORMANCE (int): Indicates a potential increase or decrease in performance. + """ + + CATEGORY_UNSPECIFIED = 0 + COST = 1 + SECURITY = 2 + PERFORMANCE = 3 + + +class RecommendationStateInfo(object): + class State(enum.IntEnum): + """ + Represents Recommendation State + + Attributes: + STATE_UNSPECIFIED (int): Default state. Don't use directly. + ACTIVE (int): Recommendation is active and can be applied. Recommendations content can + be updated by Google. + + ACTIVE recommendations can be marked as CLAIMED, SUCCEEDED, or FAILED. + CLAIMED (int): Recommendation is in claimed state. Recommendations content is + immutable and cannot be updated by Google. + + CLAIMED recommendations can be marked as CLAIMED, SUCCEEDED, or FAILED. + SUCCEEDED (int): Recommendation is in succeeded state. Recommendations content is + immutable and cannot be updated by Google. + + SUCCEEDED recommendations can be marked as SUCCEEDED, or FAILED. + FAILED (int): Recommendation is in failed state. Recommendations content is immutable + and cannot be updated by Google. + + FAILED recommendations can be marked as SUCCEEDED, or FAILED. + DISMISSED (int): Recommendation is in dismissed state. Recommendation content can be + updated by Google. + + DISMISSED recommendations can be marked as ACTIVE. + """ + + STATE_UNSPECIFIED = 0 + ACTIVE = 1 + CLAIMED = 6 + SUCCEEDED = 3 + FAILED = 4 + DISMISSED = 5 diff --git a/recommender/google/cloud/recommender_v1beta1/gapic/recommender_client.py b/recommender/google/cloud/recommender_v1beta1/gapic/recommender_client.py new file mode 100644 index 000000000000..deb485bb83f3 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/gapic/recommender_client.py @@ -0,0 +1,670 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Accesses the google.cloud.recommender.v1beta1 Recommender API.""" + +import functools +import pkg_resources +import warnings + +from google.oauth2 import service_account +import google.api_core.client_options +import google.api_core.gapic_v1.client_info +import google.api_core.gapic_v1.config +import google.api_core.gapic_v1.method +import google.api_core.gapic_v1.routing_header +import google.api_core.grpc_helpers +import google.api_core.page_iterator +import google.api_core.path_template +import grpc + +from google.cloud.recommender_v1beta1.gapic import enums +from google.cloud.recommender_v1beta1.gapic import recommender_client_config +from google.cloud.recommender_v1beta1.gapic.transports import recommender_grpc_transport +from google.cloud.recommender_v1beta1.proto import recommendation_pb2 +from google.cloud.recommender_v1beta1.proto import recommender_service_pb2 +from google.cloud.recommender_v1beta1.proto import recommender_service_pb2_grpc + + +_GAPIC_LIBRARY_VERSION = pkg_resources.get_distribution( + "google-cloud-recommender" +).version + + +class RecommenderClient(object): + """ + Provides recommendations for cloud customers for various categories like + performance optimization, cost savings, reliability, feature discovery, etc. + These recommendations are generated automatically based on analysis of user + resources, configuration and monitoring metrics. + """ + + SERVICE_ADDRESS = "recommender.googleapis.com:443" + """The default address of the service.""" + + # The name of the interface for this client. This is the key used to + # find the method configuration in the client_config dictionary. + _INTERFACE_NAME = "google.cloud.recommender.v1beta1.Recommender" + + @classmethod + def from_service_account_file(cls, filename, *args, **kwargs): + """Creates an instance of this client using the provided credentials + file. + + Args: + filename (str): The path to the service account private key json + file. + args: Additional arguments to pass to the constructor. + kwargs: Additional arguments to pass to the constructor. + + Returns: + RecommenderClient: The constructed client. + """ + credentials = service_account.Credentials.from_service_account_file(filename) + kwargs["credentials"] = credentials + return cls(*args, **kwargs) + + from_service_account_json = from_service_account_file + + @classmethod + def recommendation_path(cls, project, location, recommender, recommendation): + """Return a fully-qualified recommendation string.""" + return google.api_core.path_template.expand( + "projects/{project}/locations/{location}/recommenders/{recommender}/recommendations/{recommendation}", + project=project, + location=location, + recommender=recommender, + recommendation=recommendation, + ) + + @classmethod + def recommender_path(cls, project, location, recommender): + """Return a fully-qualified recommender string.""" + return google.api_core.path_template.expand( + "projects/{project}/locations/{location}/recommenders/{recommender}", + project=project, + location=location, + recommender=recommender, + ) + + def __init__( + self, + transport=None, + channel=None, + credentials=None, + client_config=None, + client_info=None, + client_options=None, + ): + """Constructor. + + Args: + transport (Union[~.RecommenderGrpcTransport, + Callable[[~.Credentials, type], ~.RecommenderGrpcTransport]): A transport + instance, responsible for actually making the API calls. + The default transport uses the gRPC protocol. + This argument may also be a callable which returns a + transport instance. Callables will be sent the credentials + as the first argument and the default transport class as + the second argument. + channel (grpc.Channel): DEPRECATED. A ``Channel`` instance + through which to make calls. This argument is mutually exclusive + with ``credentials``; providing both will raise an exception. + credentials (google.auth.credentials.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If none + are specified, the client will attempt to ascertain the + credentials from the environment. + This argument is mutually exclusive with providing a + transport instance to ``transport``; doing so will raise + an exception. + client_config (dict): DEPRECATED. A dictionary of call options for + each method. If not specified, the default configuration is used. + client_info (google.api_core.gapic_v1.client_info.ClientInfo): + The client info used to send a user-agent string along with + API requests. If ``None``, then default info will be used. + Generally, you only need to set this if you're developing + your own client library. + client_options (Union[dict, google.api_core.client_options.ClientOptions]): + Client options used to set user options on the client. API Endpoint + should be set through client_options. + """ + # Raise deprecation warnings for things we want to go away. + if client_config is not None: + warnings.warn( + "The `client_config` argument is deprecated.", + PendingDeprecationWarning, + stacklevel=2, + ) + else: + client_config = recommender_client_config.config + + if channel: + warnings.warn( + "The `channel` argument is deprecated; use " "`transport` instead.", + PendingDeprecationWarning, + stacklevel=2, + ) + + api_endpoint = self.SERVICE_ADDRESS + if client_options: + if type(client_options) == dict: + client_options = google.api_core.client_options.from_dict( + client_options + ) + if client_options.api_endpoint: + api_endpoint = client_options.api_endpoint + + # Instantiate the transport. + # The transport is responsible for handling serialization and + # deserialization and actually sending data to the service. + if transport: + if callable(transport): + self.transport = transport( + credentials=credentials, + default_class=recommender_grpc_transport.RecommenderGrpcTransport, + address=api_endpoint, + ) + else: + if credentials: + raise ValueError( + "Received both a transport instance and " + "credentials; these are mutually exclusive." + ) + self.transport = transport + else: + self.transport = recommender_grpc_transport.RecommenderGrpcTransport( + address=api_endpoint, channel=channel, credentials=credentials + ) + + if client_info is None: + client_info = google.api_core.gapic_v1.client_info.ClientInfo( + gapic_version=_GAPIC_LIBRARY_VERSION + ) + else: + client_info.gapic_version = _GAPIC_LIBRARY_VERSION + self._client_info = client_info + + # Parse out the default settings for retry and timeout for each RPC + # from the client configuration. + # (Ordinarily, these are the defaults specified in the `*_config.py` + # file next to this one.) + self._method_configs = google.api_core.gapic_v1.config.parse_method_configs( + client_config["interfaces"][self._INTERFACE_NAME] + ) + + # Save a dictionary of cached API call functions. + # These are the actual callables which invoke the proper + # transport methods, wrapped with `wrap_method` to add retry, + # timeout, and the like. + self._inner_api_calls = {} + + # Service calls + def list_recommendations( + self, + parent, + page_size=None, + filter_=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): + """ + Lists recommendations for a Cloud project. Requires the + recommender.\*.list IAM permission for the specified recommender. + + Example: + >>> from google.cloud import recommender_v1beta1 + >>> + >>> client = recommender_v1beta1.RecommenderClient() + >>> + >>> parent = client.recommender_path('[PROJECT]', '[LOCATION]', '[RECOMMENDER]') + >>> + >>> # Iterate over all results + >>> for element in client.list_recommendations(parent): + ... # process element + ... pass + >>> + >>> + >>> # Alternatively: + >>> + >>> # Iterate over results one page at a time + >>> for page in client.list_recommendations(parent).pages: + ... for element in page: + ... # process element + ... pass + + Args: + parent (str): Required. The container resource on which to execute the request. + Acceptable formats: + + 1. + + "projects/[PROJECT\_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER\_ID]", + + LOCATION here refers to GCP Locations: + https://cloud.google.com/about/locations/ + page_size (int): The maximum number of resources contained in the + underlying API response. If page streaming is performed per- + resource, this parameter does not affect the return value. If page + streaming is performed per-page, this determines the maximum number + of resources in a page. + filter_ (str): Filter expression to restrict the recommendations returned. Supported + filter fields: state\_info.state Eg: \`state\_info.state:"DISMISSED" or + state\_info.state:"FAILED" + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will + be retried using a default configuration. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.api_core.page_iterator.PageIterator` instance. + An iterable of :class:`~google.cloud.recommender_v1beta1.types.Recommendation` instances. + You can also iterate over the pages of the response + using its `pages` property. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + # Wrap the transport method to add retry and timeout logic. + if "list_recommendations" not in self._inner_api_calls: + self._inner_api_calls[ + "list_recommendations" + ] = google.api_core.gapic_v1.method.wrap_method( + self.transport.list_recommendations, + default_retry=self._method_configs["ListRecommendations"].retry, + default_timeout=self._method_configs["ListRecommendations"].timeout, + client_info=self._client_info, + ) + + request = recommender_service_pb2.ListRecommendationsRequest( + parent=parent, page_size=page_size, filter=filter_ + ) + if metadata is None: + metadata = [] + metadata = list(metadata) + try: + routing_header = [("parent", parent)] + except AttributeError: + pass + else: + routing_metadata = google.api_core.gapic_v1.routing_header.to_grpc_metadata( + routing_header + ) + metadata.append(routing_metadata) + + iterator = google.api_core.page_iterator.GRPCIterator( + client=None, + method=functools.partial( + self._inner_api_calls["list_recommendations"], + retry=retry, + timeout=timeout, + metadata=metadata, + ), + request=request, + items_field="recommendations", + request_token_field="page_token", + response_token_field="next_page_token", + ) + return iterator + + def get_recommendation( + self, + name, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): + """ + Gets the requested recommendation. Requires the recommender.\*.get IAM + permission for the specified recommender. + + Example: + >>> from google.cloud import recommender_v1beta1 + >>> + >>> client = recommender_v1beta1.RecommenderClient() + >>> + >>> name = client.recommendation_path('[PROJECT]', '[LOCATION]', '[RECOMMENDER]', '[RECOMMENDATION]') + >>> + >>> response = client.get_recommendation(name) + + Args: + name (str): Name of the recommendation. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will + be retried using a default configuration. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.cloud.recommender_v1beta1.types.Recommendation` instance. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + # Wrap the transport method to add retry and timeout logic. + if "get_recommendation" not in self._inner_api_calls: + self._inner_api_calls[ + "get_recommendation" + ] = google.api_core.gapic_v1.method.wrap_method( + self.transport.get_recommendation, + default_retry=self._method_configs["GetRecommendation"].retry, + default_timeout=self._method_configs["GetRecommendation"].timeout, + client_info=self._client_info, + ) + + request = recommender_service_pb2.GetRecommendationRequest(name=name) + if metadata is None: + metadata = [] + metadata = list(metadata) + try: + routing_header = [("name", name)] + except AttributeError: + pass + else: + routing_metadata = google.api_core.gapic_v1.routing_header.to_grpc_metadata( + routing_header + ) + metadata.append(routing_metadata) + + return self._inner_api_calls["get_recommendation"]( + request, retry=retry, timeout=timeout, metadata=metadata + ) + + def mark_recommendation_claimed( + self, + name, + etag, + state_metadata=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): + """ + Mark the Recommendation State as Claimed. Users can use this method to + indicate to the Recommender API that they are starting to apply the + recommendation themselves. This stops the recommendation content from + being updated. + + MarkRecommendationClaimed can be applied to recommendations in CLAIMED, + SUCCEEDED, FAILED, or ACTIVE state. + + Requires the recommender.\*.update IAM permission for the specified + recommender. + + Example: + >>> from google.cloud import recommender_v1beta1 + >>> + >>> client = recommender_v1beta1.RecommenderClient() + >>> + >>> name = client.recommendation_path('[PROJECT]', '[LOCATION]', '[RECOMMENDER]', '[RECOMMENDATION]') + >>> + >>> # TODO: Initialize `etag`: + >>> etag = '' + >>> + >>> response = client.mark_recommendation_claimed(name, etag) + + Args: + name (str): Name of the recommendation. + etag (str): Fingerprint of the Recommendation. Provides optimistic locking. + state_metadata (dict[str -> str]): State properties to include with this state. Overwrites any existing + ``state_metadata``. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will + be retried using a default configuration. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.cloud.recommender_v1beta1.types.Recommendation` instance. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + # Wrap the transport method to add retry and timeout logic. + if "mark_recommendation_claimed" not in self._inner_api_calls: + self._inner_api_calls[ + "mark_recommendation_claimed" + ] = google.api_core.gapic_v1.method.wrap_method( + self.transport.mark_recommendation_claimed, + default_retry=self._method_configs["MarkRecommendationClaimed"].retry, + default_timeout=self._method_configs[ + "MarkRecommendationClaimed" + ].timeout, + client_info=self._client_info, + ) + + request = recommender_service_pb2.MarkRecommendationClaimedRequest( + name=name, etag=etag, state_metadata=state_metadata + ) + if metadata is None: + metadata = [] + metadata = list(metadata) + try: + routing_header = [("name", name)] + except AttributeError: + pass + else: + routing_metadata = google.api_core.gapic_v1.routing_header.to_grpc_metadata( + routing_header + ) + metadata.append(routing_metadata) + + return self._inner_api_calls["mark_recommendation_claimed"]( + request, retry=retry, timeout=timeout, metadata=metadata + ) + + def mark_recommendation_succeeded( + self, + name, + etag, + state_metadata=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): + """ + Mark the Recommendation State as Succeeded. Users can use this method to + indicate to the Recommender API that they have applied the + recommendation themselves, and the operation was successful. This stops + the recommendation content from being updated. + + MarkRecommendationSucceeded can be applied to recommendations in ACTIVE, + CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.\*.update IAM permission for the specified + recommender. + + Example: + >>> from google.cloud import recommender_v1beta1 + >>> + >>> client = recommender_v1beta1.RecommenderClient() + >>> + >>> name = client.recommendation_path('[PROJECT]', '[LOCATION]', '[RECOMMENDER]', '[RECOMMENDATION]') + >>> + >>> # TODO: Initialize `etag`: + >>> etag = '' + >>> + >>> response = client.mark_recommendation_succeeded(name, etag) + + Args: + name (str): Name of the recommendation. + etag (str): Fingerprint of the Recommendation. Provides optimistic locking. + state_metadata (dict[str -> str]): State properties to include with this state. Overwrites any existing + ``state_metadata``. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will + be retried using a default configuration. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.cloud.recommender_v1beta1.types.Recommendation` instance. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + # Wrap the transport method to add retry and timeout logic. + if "mark_recommendation_succeeded" not in self._inner_api_calls: + self._inner_api_calls[ + "mark_recommendation_succeeded" + ] = google.api_core.gapic_v1.method.wrap_method( + self.transport.mark_recommendation_succeeded, + default_retry=self._method_configs["MarkRecommendationSucceeded"].retry, + default_timeout=self._method_configs[ + "MarkRecommendationSucceeded" + ].timeout, + client_info=self._client_info, + ) + + request = recommender_service_pb2.MarkRecommendationSucceededRequest( + name=name, etag=etag, state_metadata=state_metadata + ) + if metadata is None: + metadata = [] + metadata = list(metadata) + try: + routing_header = [("name", name)] + except AttributeError: + pass + else: + routing_metadata = google.api_core.gapic_v1.routing_header.to_grpc_metadata( + routing_header + ) + metadata.append(routing_metadata) + + return self._inner_api_calls["mark_recommendation_succeeded"]( + request, retry=retry, timeout=timeout, metadata=metadata + ) + + def mark_recommendation_failed( + self, + name, + etag, + state_metadata=None, + retry=google.api_core.gapic_v1.method.DEFAULT, + timeout=google.api_core.gapic_v1.method.DEFAULT, + metadata=None, + ): + """ + Mark the Recommendation State as Failed. Users can use this method to + indicate to the Recommender API that they have applied the + recommendation themselves, and the operation failed. This stops the + recommendation content from being updated. + + MarkRecommendationFailed can be applied to recommendations in ACTIVE, + CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.\*.update IAM permission for the specified + recommender. + + Example: + >>> from google.cloud import recommender_v1beta1 + >>> + >>> client = recommender_v1beta1.RecommenderClient() + >>> + >>> name = client.recommendation_path('[PROJECT]', '[LOCATION]', '[RECOMMENDER]', '[RECOMMENDATION]') + >>> + >>> # TODO: Initialize `etag`: + >>> etag = '' + >>> + >>> response = client.mark_recommendation_failed(name, etag) + + Args: + name (str): Name of the recommendation. + etag (str): Fingerprint of the Recommendation. Provides optimistic locking. + state_metadata (dict[str -> str]): State properties to include with this state. Overwrites any existing + ``state_metadata``. + retry (Optional[google.api_core.retry.Retry]): A retry object used + to retry requests. If ``None`` is specified, requests will + be retried using a default configuration. + timeout (Optional[float]): The amount of time, in seconds, to wait + for the request to complete. Note that if ``retry`` is + specified, the timeout applies to each individual attempt. + metadata (Optional[Sequence[Tuple[str, str]]]): Additional metadata + that is provided to the method. + + Returns: + A :class:`~google.cloud.recommender_v1beta1.types.Recommendation` instance. + + Raises: + google.api_core.exceptions.GoogleAPICallError: If the request + failed for any reason. + google.api_core.exceptions.RetryError: If the request failed due + to a retryable error and retry attempts failed. + ValueError: If the parameters are invalid. + """ + # Wrap the transport method to add retry and timeout logic. + if "mark_recommendation_failed" not in self._inner_api_calls: + self._inner_api_calls[ + "mark_recommendation_failed" + ] = google.api_core.gapic_v1.method.wrap_method( + self.transport.mark_recommendation_failed, + default_retry=self._method_configs["MarkRecommendationFailed"].retry, + default_timeout=self._method_configs[ + "MarkRecommendationFailed" + ].timeout, + client_info=self._client_info, + ) + + request = recommender_service_pb2.MarkRecommendationFailedRequest( + name=name, etag=etag, state_metadata=state_metadata + ) + if metadata is None: + metadata = [] + metadata = list(metadata) + try: + routing_header = [("name", name)] + except AttributeError: + pass + else: + routing_metadata = google.api_core.gapic_v1.routing_header.to_grpc_metadata( + routing_header + ) + metadata.append(routing_metadata) + + return self._inner_api_calls["mark_recommendation_failed"]( + request, retry=retry, timeout=timeout, metadata=metadata + ) diff --git a/recommender/google/cloud/recommender_v1beta1/gapic/recommender_client_config.py b/recommender/google/cloud/recommender_v1beta1/gapic/recommender_client_config.py new file mode 100644 index 000000000000..a1a36482eecd --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/gapic/recommender_client_config.py @@ -0,0 +1,48 @@ +config = { + "interfaces": { + "google.cloud.recommender.v1beta1.Recommender": { + "retry_codes": { + "idempotent": ["DEADLINE_EXCEEDED", "UNAVAILABLE"], + "non_idempotent": [], + }, + "retry_params": { + "default": { + "initial_retry_delay_millis": 100, + "retry_delay_multiplier": 1.3, + "max_retry_delay_millis": 60000, + "initial_rpc_timeout_millis": 20000, + "rpc_timeout_multiplier": 1.0, + "max_rpc_timeout_millis": 20000, + "total_timeout_millis": 600000, + } + }, + "methods": { + "ListRecommendations": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default", + }, + "GetRecommendation": { + "timeout_millis": 60000, + "retry_codes_name": "idempotent", + "retry_params_name": "default", + }, + "MarkRecommendationClaimed": { + "timeout_millis": 60000, + "retry_codes_name": "non_idempotent", + "retry_params_name": "default", + }, + "MarkRecommendationSucceeded": { + "timeout_millis": 60000, + "retry_codes_name": "non_idempotent", + "retry_params_name": "default", + }, + "MarkRecommendationFailed": { + "timeout_millis": 60000, + "retry_codes_name": "non_idempotent", + "retry_params_name": "default", + }, + }, + } + } +} diff --git a/recommender/google/cloud/recommender_v1beta1/gapic/transports/__init__.py b/recommender/google/cloud/recommender_v1beta1/gapic/transports/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/recommender/google/cloud/recommender_v1beta1/gapic/transports/recommender_grpc_transport.py b/recommender/google/cloud/recommender_v1beta1/gapic/transports/recommender_grpc_transport.py new file mode 100644 index 000000000000..cc3af3d44211 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/gapic/transports/recommender_grpc_transport.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import google.api_core.grpc_helpers + +from google.cloud.recommender_v1beta1.proto import recommender_service_pb2_grpc + + +class RecommenderGrpcTransport(object): + """gRPC transport class providing stubs for + google.cloud.recommender.v1beta1 Recommender API. + + The transport provides access to the raw gRPC stubs, + which can be used to take advantage of advanced + features of gRPC. + """ + + # The scopes needed to make gRPC calls to all of the methods defined + # in this service. + _OAUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) + + def __init__( + self, channel=None, credentials=None, address="recommender.googleapis.com:443" + ): + """Instantiate the transport class. + + Args: + channel (grpc.Channel): A ``Channel`` instance through + which to make calls. This argument is mutually exclusive + with ``credentials``; providing both will raise an exception. + credentials (google.auth.credentials.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If none + are specified, the client will attempt to ascertain the + credentials from the environment. + address (str): The address where the service is hosted. + """ + # If both `channel` and `credentials` are specified, raise an + # exception (channels come with credentials baked in already). + if channel is not None and credentials is not None: + raise ValueError( + "The `channel` and `credentials` arguments are mutually " "exclusive." + ) + + # Create the channel. + if channel is None: + channel = self.create_channel( + address=address, + credentials=credentials, + options={ + "grpc.max_send_message_length": -1, + "grpc.max_receive_message_length": -1, + }.items(), + ) + + self._channel = channel + + # gRPC uses objects called "stubs" that are bound to the + # channel and provide a basic method for each RPC. + self._stubs = { + "recommender_stub": recommender_service_pb2_grpc.RecommenderStub(channel) + } + + @classmethod + def create_channel( + cls, address="recommender.googleapis.com:443", credentials=None, **kwargs + ): + """Create and return a gRPC channel object. + + Args: + address (str): The host for the channel to use. + credentials (~.Credentials): The + authorization credentials to attach to requests. These + credentials identify this application to the service. If + none are specified, the client will attempt to ascertain + the credentials from the environment. + kwargs (dict): Keyword arguments, which are passed to the + channel creation. + + Returns: + grpc.Channel: A gRPC channel object. + """ + return google.api_core.grpc_helpers.create_channel( + address, credentials=credentials, scopes=cls._OAUTH_SCOPES, **kwargs + ) + + @property + def channel(self): + """The gRPC channel used by the transport. + + Returns: + grpc.Channel: A gRPC channel object. + """ + return self._channel + + @property + def list_recommendations(self): + """Return the gRPC stub for :meth:`RecommenderClient.list_recommendations`. + + Lists recommendations for a Cloud project. Requires the + recommender.\*.list IAM permission for the specified recommender. + + Returns: + Callable: A callable which accepts the appropriate + deserialized request object and returns a + deserialized response object. + """ + return self._stubs["recommender_stub"].ListRecommendations + + @property + def get_recommendation(self): + """Return the gRPC stub for :meth:`RecommenderClient.get_recommendation`. + + Gets the requested recommendation. Requires the recommender.\*.get IAM + permission for the specified recommender. + + Returns: + Callable: A callable which accepts the appropriate + deserialized request object and returns a + deserialized response object. + """ + return self._stubs["recommender_stub"].GetRecommendation + + @property + def mark_recommendation_claimed(self): + """Return the gRPC stub for :meth:`RecommenderClient.mark_recommendation_claimed`. + + Mark the Recommendation State as Claimed. Users can use this method to + indicate to the Recommender API that they are starting to apply the + recommendation themselves. This stops the recommendation content from + being updated. + + MarkRecommendationClaimed can be applied to recommendations in CLAIMED, + SUCCEEDED, FAILED, or ACTIVE state. + + Requires the recommender.\*.update IAM permission for the specified + recommender. + + Returns: + Callable: A callable which accepts the appropriate + deserialized request object and returns a + deserialized response object. + """ + return self._stubs["recommender_stub"].MarkRecommendationClaimed + + @property + def mark_recommendation_succeeded(self): + """Return the gRPC stub for :meth:`RecommenderClient.mark_recommendation_succeeded`. + + Mark the Recommendation State as Succeeded. Users can use this method to + indicate to the Recommender API that they have applied the + recommendation themselves, and the operation was successful. This stops + the recommendation content from being updated. + + MarkRecommendationSucceeded can be applied to recommendations in ACTIVE, + CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.\*.update IAM permission for the specified + recommender. + + Returns: + Callable: A callable which accepts the appropriate + deserialized request object and returns a + deserialized response object. + """ + return self._stubs["recommender_stub"].MarkRecommendationSucceeded + + @property + def mark_recommendation_failed(self): + """Return the gRPC stub for :meth:`RecommenderClient.mark_recommendation_failed`. + + Mark the Recommendation State as Failed. Users can use this method to + indicate to the Recommender API that they have applied the + recommendation themselves, and the operation failed. This stops the + recommendation content from being updated. + + MarkRecommendationFailed can be applied to recommendations in ACTIVE, + CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.\*.update IAM permission for the specified + recommender. + + Returns: + Callable: A callable which accepts the appropriate + deserialized request object and returns a + deserialized response object. + """ + return self._stubs["recommender_stub"].MarkRecommendationFailed diff --git a/recommender/google/cloud/recommender_v1beta1/proto/__init__.py b/recommender/google/cloud/recommender_v1beta1/proto/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2.py b/recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2.py new file mode 100644 index 000000000000..e7d5913a69a3 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2.py @@ -0,0 +1,1119 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/cloud/recommender_v1beta1/proto/recommendation.proto + +import sys + +_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode("latin1")) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2 +from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 +from google.type import money_pb2 as google_dot_type_dot_money__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name="google/cloud/recommender_v1beta1/proto/recommendation.proto", + package="google.cloud.recommender.v1beta1", + syntax="proto3", + serialized_options=_b( + "\n$com.google.cloud.recommender.v1beta1P\001ZKgoogle.golang.org/genproto/googleapis/cloud/recommender/v1beta1;recommender\242\002\004CREC\252\002 Google.Cloud.Recommender.V1Beta1" + ), + serialized_pb=_b( + '\n;google/cloud/recommender_v1beta1/proto/recommendation.proto\x12 google.cloud.recommender.v1beta1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17google/type/money.proto"\xb5\x03\n\x0eRecommendation\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x1b\n\x13recommender_subtype\x18\x0c \x01(\t\x12\x35\n\x11last_refresh_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12@\n\x0eprimary_impact\x18\x05 \x01(\x0b\x32(.google.cloud.recommender.v1beta1.Impact\x12\x43\n\x11\x61\x64\x64itional_impact\x18\x06 \x03(\x0b\x32(.google.cloud.recommender.v1beta1.Impact\x12H\n\x07\x63ontent\x18\x07 \x01(\x0b\x32\x37.google.cloud.recommender.v1beta1.RecommendationContent\x12M\n\nstate_info\x18\n \x01(\x0b\x32\x39.google.cloud.recommender.v1beta1.RecommendationStateInfo\x12\x0c\n\x04\x65tag\x18\x0b \x01(\t"c\n\x15RecommendationContent\x12J\n\x10operation_groups\x18\x02 \x03(\x0b\x32\x30.google.cloud.recommender.v1beta1.OperationGroup"Q\n\x0eOperationGroup\x12?\n\noperations\x18\x01 \x03(\x0b\x32+.google.cloud.recommender.v1beta1.Operation"\xc7\x02\n\tOperation\x12\x0e\n\x06\x61\x63tion\x18\x01 \x01(\t\x12\x15\n\rresource_type\x18\x02 \x01(\t\x12\x10\n\x08resource\x18\x03 \x01(\t\x12\x0c\n\x04path\x18\x04 \x01(\t\x12\x17\n\x0fsource_resource\x18\x05 \x01(\t\x12\x13\n\x0bsource_path\x18\x06 \x01(\t\x12%\n\x05value\x18\x07 \x01(\x0b\x32\x16.google.protobuf.Value\x12R\n\x0cpath_filters\x18\x08 \x03(\x0b\x32<.google.cloud.recommender.v1beta1.Operation.PathFiltersEntry\x1aJ\n\x10PathFiltersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12%\n\x05value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value:\x02\x38\x01"_\n\x0e\x43ostProjection\x12 \n\x04\x63ost\x18\x01 \x01(\x0b\x32\x12.google.type.Money\x12+\n\x08\x64uration\x18\x02 \x01(\x0b\x32\x19.google.protobuf.Duration"\xf7\x01\n\x06Impact\x12\x43\n\x08\x63\x61tegory\x18\x01 \x01(\x0e\x32\x31.google.cloud.recommender.v1beta1.Impact.Category\x12K\n\x0f\x63ost_projection\x18\x64 \x01(\x0b\x32\x30.google.cloud.recommender.v1beta1.CostProjectionH\x00"M\n\x08\x43\x61tegory\x12\x18\n\x14\x43\x41TEGORY_UNSPECIFIED\x10\x00\x12\x08\n\x04\x43OST\x10\x01\x12\x0c\n\x08SECURITY\x10\x02\x12\x0f\n\x0bPERFORMANCE\x10\x03\x42\x0c\n\nprojection"\xe8\x02\n\x17RecommendationStateInfo\x12N\n\x05state\x18\x01 \x01(\x0e\x32?.google.cloud.recommender.v1beta1.RecommendationStateInfo.State\x12\x64\n\x0estate_metadata\x18\x02 \x03(\x0b\x32L.google.cloud.recommender.v1beta1.RecommendationStateInfo.StateMetadataEntry\x1a\x34\n\x12StateMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01"a\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\n\n\x06\x41\x43TIVE\x10\x01\x12\x0b\n\x07\x43LAIMED\x10\x06\x12\r\n\tSUCCEEDED\x10\x03\x12\n\n\x06\x46\x41ILED\x10\x04\x12\r\n\tDISMISSED\x10\x05\x42\x9f\x01\n$com.google.cloud.recommender.v1beta1P\x01ZKgoogle.golang.org/genproto/googleapis/cloud/recommender/v1beta1;recommender\xa2\x02\x04\x43REC\xaa\x02 Google.Cloud.Recommender.V1Beta1b\x06proto3' + ), + dependencies=[ + google_dot_protobuf_dot_duration__pb2.DESCRIPTOR, + google_dot_protobuf_dot_struct__pb2.DESCRIPTOR, + google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR, + google_dot_type_dot_money__pb2.DESCRIPTOR, + ], +) + + +_IMPACT_CATEGORY = _descriptor.EnumDescriptor( + name="Category", + full_name="google.cloud.recommender.v1beta1.Impact.Category", + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name="CATEGORY_UNSPECIFIED", + index=0, + number=0, + serialized_options=None, + type=None, + ), + _descriptor.EnumValueDescriptor( + name="COST", index=1, number=1, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name="SECURITY", index=2, number=2, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name="PERFORMANCE", index=3, number=3, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=1425, + serialized_end=1502, +) +_sym_db.RegisterEnumDescriptor(_IMPACT_CATEGORY) + +_RECOMMENDATIONSTATEINFO_STATE = _descriptor.EnumDescriptor( + name="State", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo.State", + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name="STATE_UNSPECIFIED", + index=0, + number=0, + serialized_options=None, + type=None, + ), + _descriptor.EnumValueDescriptor( + name="ACTIVE", index=1, number=1, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name="CLAIMED", index=2, number=6, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name="SUCCEEDED", index=3, number=3, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name="FAILED", index=4, number=4, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name="DISMISSED", index=5, number=5, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=1782, + serialized_end=1879, +) +_sym_db.RegisterEnumDescriptor(_RECOMMENDATIONSTATEINFO_STATE) + + +_RECOMMENDATION = _descriptor.Descriptor( + name="Recommendation", + full_name="google.cloud.recommender.v1beta1.Recommendation", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="name", + full_name="google.cloud.recommender.v1beta1.Recommendation.name", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="description", + full_name="google.cloud.recommender.v1beta1.Recommendation.description", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="recommender_subtype", + full_name="google.cloud.recommender.v1beta1.Recommendation.recommender_subtype", + index=2, + number=12, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="last_refresh_time", + full_name="google.cloud.recommender.v1beta1.Recommendation.last_refresh_time", + index=3, + number=4, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="primary_impact", + full_name="google.cloud.recommender.v1beta1.Recommendation.primary_impact", + index=4, + number=5, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="additional_impact", + full_name="google.cloud.recommender.v1beta1.Recommendation.additional_impact", + index=5, + number=6, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="content", + full_name="google.cloud.recommender.v1beta1.Recommendation.content", + index=6, + number=7, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="state_info", + full_name="google.cloud.recommender.v1beta1.Recommendation.state_info", + index=7, + number=10, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="etag", + full_name="google.cloud.recommender.v1beta1.Recommendation.etag", + index=8, + number=11, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=218, + serialized_end=655, +) + + +_RECOMMENDATIONCONTENT = _descriptor.Descriptor( + name="RecommendationContent", + full_name="google.cloud.recommender.v1beta1.RecommendationContent", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="operation_groups", + full_name="google.cloud.recommender.v1beta1.RecommendationContent.operation_groups", + index=0, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ) + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=657, + serialized_end=756, +) + + +_OPERATIONGROUP = _descriptor.Descriptor( + name="OperationGroup", + full_name="google.cloud.recommender.v1beta1.OperationGroup", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="operations", + full_name="google.cloud.recommender.v1beta1.OperationGroup.operations", + index=0, + number=1, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ) + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=758, + serialized_end=839, +) + + +_OPERATION_PATHFILTERSENTRY = _descriptor.Descriptor( + name="PathFiltersEntry", + full_name="google.cloud.recommender.v1beta1.Operation.PathFiltersEntry", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="key", + full_name="google.cloud.recommender.v1beta1.Operation.PathFiltersEntry.key", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="google.cloud.recommender.v1beta1.Operation.PathFiltersEntry.value", + index=1, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=_b("8\001"), + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1095, + serialized_end=1169, +) + +_OPERATION = _descriptor.Descriptor( + name="Operation", + full_name="google.cloud.recommender.v1beta1.Operation", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="action", + full_name="google.cloud.recommender.v1beta1.Operation.action", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="resource_type", + full_name="google.cloud.recommender.v1beta1.Operation.resource_type", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="resource", + full_name="google.cloud.recommender.v1beta1.Operation.resource", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="path", + full_name="google.cloud.recommender.v1beta1.Operation.path", + index=3, + number=4, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="source_resource", + full_name="google.cloud.recommender.v1beta1.Operation.source_resource", + index=4, + number=5, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="source_path", + full_name="google.cloud.recommender.v1beta1.Operation.source_path", + index=5, + number=6, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="google.cloud.recommender.v1beta1.Operation.value", + index=6, + number=7, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="path_filters", + full_name="google.cloud.recommender.v1beta1.Operation.path_filters", + index=7, + number=8, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_OPERATION_PATHFILTERSENTRY], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=842, + serialized_end=1169, +) + + +_COSTPROJECTION = _descriptor.Descriptor( + name="CostProjection", + full_name="google.cloud.recommender.v1beta1.CostProjection", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="cost", + full_name="google.cloud.recommender.v1beta1.CostProjection.cost", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="duration", + full_name="google.cloud.recommender.v1beta1.CostProjection.duration", + index=1, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1171, + serialized_end=1266, +) + + +_IMPACT = _descriptor.Descriptor( + name="Impact", + full_name="google.cloud.recommender.v1beta1.Impact", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="category", + full_name="google.cloud.recommender.v1beta1.Impact.category", + index=0, + number=1, + type=14, + cpp_type=8, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="cost_projection", + full_name="google.cloud.recommender.v1beta1.Impact.cost_projection", + index=1, + number=100, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_IMPACT_CATEGORY], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="projection", + full_name="google.cloud.recommender.v1beta1.Impact.projection", + index=0, + containing_type=None, + fields=[], + ) + ], + serialized_start=1269, + serialized_end=1516, +) + + +_RECOMMENDATIONSTATEINFO_STATEMETADATAENTRY = _descriptor.Descriptor( + name="StateMetadataEntry", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo.StateMetadataEntry", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="key", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo.StateMetadataEntry.key", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo.StateMetadataEntry.value", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=_b("8\001"), + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1728, + serialized_end=1780, +) + +_RECOMMENDATIONSTATEINFO = _descriptor.Descriptor( + name="RecommendationStateInfo", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="state", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo.state", + index=0, + number=1, + type=14, + cpp_type=8, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="state_metadata", + full_name="google.cloud.recommender.v1beta1.RecommendationStateInfo.state_metadata", + index=1, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_RECOMMENDATIONSTATEINFO_STATEMETADATAENTRY], + enum_types=[_RECOMMENDATIONSTATEINFO_STATE], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=1519, + serialized_end=1879, +) + +_RECOMMENDATION.fields_by_name[ + "last_refresh_time" +].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_RECOMMENDATION.fields_by_name["primary_impact"].message_type = _IMPACT +_RECOMMENDATION.fields_by_name["additional_impact"].message_type = _IMPACT +_RECOMMENDATION.fields_by_name["content"].message_type = _RECOMMENDATIONCONTENT +_RECOMMENDATION.fields_by_name["state_info"].message_type = _RECOMMENDATIONSTATEINFO +_RECOMMENDATIONCONTENT.fields_by_name["operation_groups"].message_type = _OPERATIONGROUP +_OPERATIONGROUP.fields_by_name["operations"].message_type = _OPERATION +_OPERATION_PATHFILTERSENTRY.fields_by_name[ + "value" +].message_type = google_dot_protobuf_dot_struct__pb2._VALUE +_OPERATION_PATHFILTERSENTRY.containing_type = _OPERATION +_OPERATION.fields_by_name[ + "value" +].message_type = google_dot_protobuf_dot_struct__pb2._VALUE +_OPERATION.fields_by_name["path_filters"].message_type = _OPERATION_PATHFILTERSENTRY +_COSTPROJECTION.fields_by_name[ + "cost" +].message_type = google_dot_type_dot_money__pb2._MONEY +_COSTPROJECTION.fields_by_name[ + "duration" +].message_type = google_dot_protobuf_dot_duration__pb2._DURATION +_IMPACT.fields_by_name["category"].enum_type = _IMPACT_CATEGORY +_IMPACT.fields_by_name["cost_projection"].message_type = _COSTPROJECTION +_IMPACT_CATEGORY.containing_type = _IMPACT +_IMPACT.oneofs_by_name["projection"].fields.append( + _IMPACT.fields_by_name["cost_projection"] +) +_IMPACT.fields_by_name["cost_projection"].containing_oneof = _IMPACT.oneofs_by_name[ + "projection" +] +_RECOMMENDATIONSTATEINFO_STATEMETADATAENTRY.containing_type = _RECOMMENDATIONSTATEINFO +_RECOMMENDATIONSTATEINFO.fields_by_name[ + "state" +].enum_type = _RECOMMENDATIONSTATEINFO_STATE +_RECOMMENDATIONSTATEINFO.fields_by_name[ + "state_metadata" +].message_type = _RECOMMENDATIONSTATEINFO_STATEMETADATAENTRY +_RECOMMENDATIONSTATEINFO_STATE.containing_type = _RECOMMENDATIONSTATEINFO +DESCRIPTOR.message_types_by_name["Recommendation"] = _RECOMMENDATION +DESCRIPTOR.message_types_by_name["RecommendationContent"] = _RECOMMENDATIONCONTENT +DESCRIPTOR.message_types_by_name["OperationGroup"] = _OPERATIONGROUP +DESCRIPTOR.message_types_by_name["Operation"] = _OPERATION +DESCRIPTOR.message_types_by_name["CostProjection"] = _COSTPROJECTION +DESCRIPTOR.message_types_by_name["Impact"] = _IMPACT +DESCRIPTOR.message_types_by_name["RecommendationStateInfo"] = _RECOMMENDATIONSTATEINFO +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Recommendation = _reflection.GeneratedProtocolMessageType( + "Recommendation", + (_message.Message,), + dict( + DESCRIPTOR=_RECOMMENDATION, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""A recommendation along with a suggested action. E.g., a rightsizing + recommendation for an underutilized VM, IAM role recommendations, etc + + + Attributes: + name: + Name of recommendation. A project recommendation is + represented as projects/[PROJECT\_NUMBER]/locations/[LOCATION] + /recommenders/[RECOMMENDER\_ID]/recommendations/[RECOMMENDATIO + N\_ID] + description: + Free-form human readable summary in English. The maximum + length is 500 characters. + recommender_subtype: + Contains an identifier for a subtype of recommendations + produced for the same recommender. Subtype is a function of + content and impact, meaning a new subtype will be added when + either content or primary impact category changes. Examples: + For recommender = "google.iam.policy.RoleRecommender", + recommender\_subtype can be one of + "REMOVE\_ROLE"/"REPLACE\_ROLE" + last_refresh_time: + Last time this recommendation was refreshed by the system that + created it in the first place. + primary_impact: + The primary impact that this recommendation can have while + trying to optimize for one category. + additional_impact: + Optional set of additional impact that this recommendation may + have when trying to optimize for the primary category. These + may be positive or negative. + content: + Content of the recommendation describing recommended changes + to resources. + state_info: + Information for state. Contains state and metadata. + etag: + Fingerprint of the Recommendation. Provides optimistic locking + when updating states. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.Recommendation) + ), +) +_sym_db.RegisterMessage(Recommendation) + +RecommendationContent = _reflection.GeneratedProtocolMessageType( + "RecommendationContent", + (_message.Message,), + dict( + DESCRIPTOR=_RECOMMENDATIONCONTENT, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""Contains what resources are changing and how they are changing. + + + Attributes: + operation_groups: + Operations to one or more Google Cloud resources grouped in + such a way that, all operations within one group are expected + to be performed atomically and in an order. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.RecommendationContent) + ), +) +_sym_db.RegisterMessage(RecommendationContent) + +OperationGroup = _reflection.GeneratedProtocolMessageType( + "OperationGroup", + (_message.Message,), + dict( + DESCRIPTOR=_OPERATIONGROUP, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""Group of operations that need to be performed atomically. + + + Attributes: + operations: + List of operations across one or more resources that belong to + this group. Loosely based on RFC6902 and should be performed + in the order they appear. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.OperationGroup) + ), +) +_sym_db.RegisterMessage(OperationGroup) + +Operation = _reflection.GeneratedProtocolMessageType( + "Operation", + (_message.Message,), + dict( + PathFiltersEntry=_reflection.GeneratedProtocolMessageType( + "PathFiltersEntry", + (_message.Message,), + dict( + DESCRIPTOR=_OPERATION_PATHFILTERSENTRY, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2" + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.Operation.PathFiltersEntry) + ), + ), + DESCRIPTOR=_OPERATION, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""Contains an operation for a resource inspired by the JSON-PATCH format + with support for: \* Custom filters for describing partial array patch. + \* Extended path values for describing nested arrays. \* Custom fields + for describing the resource for which the operation is being described. + \* Allows extension to custom operations not natively supported by + RFC6902. See https://tools.ietf.org/html/rfc6902 for details on the + original RFC. + + + Attributes: + action: + Type of this operation. Contains one of 'and', 'remove', + 'replace', 'move', 'copy', 'test' and custom operations. This + field is case-insensitive and always populated. + resource_type: + Type of GCP resource being modified/tested. This field is + always populated. Example: + cloudresourcemanager.googleapis.com/Project, + compute.googleapis.com/Instance + resource: + Contains the fully qualified resource name. This field is + always populated. ex: + //cloudresourcemanager.googleapis.com/projects/foo. + path: + Path to the target field being operated on. If the operation + is at the resource level, then path should be "/". This field + is always populated. + source_resource: + Can be set with action 'copy' to copy resource configuration + across different resources of the same type. Example: A + resource clone can be done via action = 'copy', path = "/", + from = "/", source\_resource = and resource\_name = . This + field is empty for all other values of ``action``. + source_path: + Can be set with action 'copy' or 'move' to indicate the source + field within resource or source\_resource, ignored if provided + for other operation types. + value: + Value for the ``path`` field. Set if action is + 'add'/'replace'/'test'. + path_filters: + Set of filters to apply if ``path`` refers to array elements + or nested array elements in order to narrow down to a single + unique element that is being tested/modified. Note that this + is intended to be an exact match per filter. Example: { + "/versions/*/name" : "it-123" + "/versions/*/targetSize/percent": 20 } Example: { + "/bindings/*/role": "roles/admin" "/bindings/*/condition" : + null } Example: { "/bindings/*/role": "roles/admin" + "/bindings/*/members/\*" : ["x@google.com", "y@google.com"] } + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.Operation) + ), +) +_sym_db.RegisterMessage(Operation) +_sym_db.RegisterMessage(Operation.PathFiltersEntry) + +CostProjection = _reflection.GeneratedProtocolMessageType( + "CostProjection", + (_message.Message,), + dict( + DESCRIPTOR=_COSTPROJECTION, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""Contains metadata about how much money a recommendation can save or + incur. + + + Attributes: + cost: + An approximate projection on amount saved or amount incurred. + Negative cost units indicate cost savings and positive cost + units indicate increase. See google.type.Money documentation + for positive/negative units. + duration: + Duration for which this cost applies. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.CostProjection) + ), +) +_sym_db.RegisterMessage(CostProjection) + +Impact = _reflection.GeneratedProtocolMessageType( + "Impact", + (_message.Message,), + dict( + DESCRIPTOR=_IMPACT, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""Contains the impact a recommendation can have for a given category. + + + Attributes: + category: + Category that is being targeted. + projection: + Contains projections (if any) for this category. + cost_projection: + Use with CategoryType.COST + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.Impact) + ), +) +_sym_db.RegisterMessage(Impact) + +RecommendationStateInfo = _reflection.GeneratedProtocolMessageType( + "RecommendationStateInfo", + (_message.Message,), + dict( + StateMetadataEntry=_reflection.GeneratedProtocolMessageType( + "StateMetadataEntry", + (_message.Message,), + dict( + DESCRIPTOR=_RECOMMENDATIONSTATEINFO_STATEMETADATAENTRY, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2" + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.RecommendationStateInfo.StateMetadataEntry) + ), + ), + DESCRIPTOR=_RECOMMENDATIONSTATEINFO, + __module__="google.cloud.recommender_v1beta1.proto.recommendation_pb2", + __doc__="""Information for state. Contains state and metadata. + + + Attributes: + state: + The state of the recommendation, Eg ACTIVE, SUCCEEDED, FAILED. + state_metadata: + A map of metadata for the state, provided by user or + automations systems. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.RecommendationStateInfo) + ), +) +_sym_db.RegisterMessage(RecommendationStateInfo) +_sym_db.RegisterMessage(RecommendationStateInfo.StateMetadataEntry) + + +DESCRIPTOR._options = None +_OPERATION_PATHFILTERSENTRY._options = None +_RECOMMENDATIONSTATEINFO_STATEMETADATAENTRY._options = None +# @@protoc_insertion_point(module_scope) diff --git a/recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2_grpc.py b/recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2_grpc.py new file mode 100644 index 000000000000..07cb78fe03a9 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/proto/recommendation_pb2_grpc.py @@ -0,0 +1,2 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc diff --git a/recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2.py b/recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2.py new file mode 100644 index 000000000000..5e7d8f029fd3 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2.py @@ -0,0 +1,924 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: google/cloud/recommender_v1beta1/proto/recommender_service.proto + +import sys + +_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode("latin1")) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 +from google.cloud.recommender_v1beta1.proto import ( + recommendation_pb2 as google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2, +) +from google.longrunning import ( + operations_pb2 as google_dot_longrunning_dot_operations__pb2, +) +from google.api import client_pb2 as google_dot_api_dot_client__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name="google/cloud/recommender_v1beta1/proto/recommender_service.proto", + package="google.cloud.recommender.v1beta1", + syntax="proto3", + serialized_options=_b( + "\n$com.google.cloud.recommender.v1beta1B\020RecommenderProtoP\001ZKgoogle.golang.org/genproto/googleapis/cloud/recommender/v1beta1;recommender\242\002\004CREC\252\002!Google.Cloud.Recommmender.V1Beta1" + ), + serialized_pb=_b( + '\n@google/cloud/recommender_v1beta1/proto/recommender_service.proto\x12 google.cloud.recommender.v1beta1\x1a\x1cgoogle/api/annotations.proto\x1a;google/cloud/recommender_v1beta1/proto/recommendation.proto\x1a#google/longrunning/operations.proto\x1a\x17google/api/client.proto"c\n\x1aListRecommendationsRequest\x12\x0e\n\x06parent\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x05 \x01(\t"\x81\x01\n\x1bListRecommendationsResponse\x12I\n\x0frecommendations\x18\x01 \x03(\x0b\x32\x30.google.cloud.recommender.v1beta1.Recommendation\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t"(\n\x18GetRecommendationRequest\x12\x0c\n\x04name\x18\x01 \x01(\t"\xe3\x01\n MarkRecommendationClaimedRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12m\n\x0estate_metadata\x18\x02 \x03(\x0b\x32U.google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.StateMetadataEntry\x12\x0c\n\x04\x65tag\x18\x03 \x01(\t\x1a\x34\n\x12StateMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01"\xe7\x01\n"MarkRecommendationSucceededRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12o\n\x0estate_metadata\x18\x02 \x03(\x0b\x32W.google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.StateMetadataEntry\x12\x0c\n\x04\x65tag\x18\x03 \x01(\t\x1a\x34\n\x12StateMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01"\xe1\x01\n\x1fMarkRecommendationFailedRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12l\n\x0estate_metadata\x18\x02 \x03(\x0b\x32T.google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.StateMetadataEntry\x12\x0c\n\x04\x65tag\x18\x03 \x01(\t\x1a\x34\n\x12StateMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x32\xf7\t\n\x0bRecommender\x12\xe3\x01\n\x13ListRecommendations\x12<.google.cloud.recommender.v1beta1.ListRecommendationsRequest\x1a=.google.cloud.recommender.v1beta1.ListRecommendationsResponse"O\x82\xd3\xe4\x93\x02I\x12G/v1beta1/{parent=projects/*/locations/*/recommenders/*}/recommendations\x12\xd2\x01\n\x11GetRecommendation\x12:.google.cloud.recommender.v1beta1.GetRecommendationRequest\x1a\x30.google.cloud.recommender.v1beta1.Recommendation"O\x82\xd3\xe4\x93\x02I\x12G/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}\x12\xf1\x01\n\x19MarkRecommendationClaimed\x12\x42.google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest\x1a\x30.google.cloud.recommender.v1beta1.Recommendation"^\x82\xd3\xe4\x93\x02X"S/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markClaimed:\x01*\x12\xf7\x01\n\x1bMarkRecommendationSucceeded\x12\x44.google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest\x1a\x30.google.cloud.recommender.v1beta1.Recommendation"`\x82\xd3\xe4\x93\x02Z"U/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markSucceeded:\x01*\x12\xee\x01\n\x18MarkRecommendationFailed\x12\x41.google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest\x1a\x30.google.cloud.recommender.v1beta1.Recommendation"]\x82\xd3\xe4\x93\x02W"R/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markFailed:\x01*\x1aN\xca\x41\x1arecommender.googleapis.com\xd2\x41.https://www.googleapis.com/auth/cloud-platformB\xb2\x01\n$com.google.cloud.recommender.v1beta1B\x10RecommenderProtoP\x01ZKgoogle.golang.org/genproto/googleapis/cloud/recommender/v1beta1;recommender\xa2\x02\x04\x43REC\xaa\x02!Google.Cloud.Recommmender.V1Beta1b\x06proto3' + ), + dependencies=[ + google_dot_api_dot_annotations__pb2.DESCRIPTOR, + google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.DESCRIPTOR, + google_dot_longrunning_dot_operations__pb2.DESCRIPTOR, + google_dot_api_dot_client__pb2.DESCRIPTOR, + ], +) + + +_LISTRECOMMENDATIONSREQUEST = _descriptor.Descriptor( + name="ListRecommendationsRequest", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="parent", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsRequest.parent", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="page_size", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsRequest.page_size", + index=1, + number=2, + type=5, + cpp_type=1, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="page_token", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsRequest.page_token", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="filter", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsRequest.filter", + index=3, + number=5, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=255, + serialized_end=354, +) + + +_LISTRECOMMENDATIONSRESPONSE = _descriptor.Descriptor( + name="ListRecommendationsResponse", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsResponse", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="recommendations", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsResponse.recommendations", + index=0, + number=1, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="next_page_token", + full_name="google.cloud.recommender.v1beta1.ListRecommendationsResponse.next_page_token", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=357, + serialized_end=486, +) + + +_GETRECOMMENDATIONREQUEST = _descriptor.Descriptor( + name="GetRecommendationRequest", + full_name="google.cloud.recommender.v1beta1.GetRecommendationRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="name", + full_name="google.cloud.recommender.v1beta1.GetRecommendationRequest.name", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ) + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=488, + serialized_end=528, +) + + +_MARKRECOMMENDATIONCLAIMEDREQUEST_STATEMETADATAENTRY = _descriptor.Descriptor( + name="StateMetadataEntry", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.StateMetadataEntry", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="key", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.StateMetadataEntry.key", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.StateMetadataEntry.value", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=_b("8\001"), + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=706, + serialized_end=758, +) + +_MARKRECOMMENDATIONCLAIMEDREQUEST = _descriptor.Descriptor( + name="MarkRecommendationClaimedRequest", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="name", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.name", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="state_metadata", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.state_metadata", + index=1, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="etag", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.etag", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_MARKRECOMMENDATIONCLAIMEDREQUEST_STATEMETADATAENTRY], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=531, + serialized_end=758, +) + + +_MARKRECOMMENDATIONSUCCEEDEDREQUEST_STATEMETADATAENTRY = _descriptor.Descriptor( + name="StateMetadataEntry", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.StateMetadataEntry", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="key", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.StateMetadataEntry.key", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.StateMetadataEntry.value", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=_b("8\001"), + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=706, + serialized_end=758, +) + +_MARKRECOMMENDATIONSUCCEEDEDREQUEST = _descriptor.Descriptor( + name="MarkRecommendationSucceededRequest", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="name", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.name", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="state_metadata", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.state_metadata", + index=1, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="etag", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.etag", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_MARKRECOMMENDATIONSUCCEEDEDREQUEST_STATEMETADATAENTRY], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=761, + serialized_end=992, +) + + +_MARKRECOMMENDATIONFAILEDREQUEST_STATEMETADATAENTRY = _descriptor.Descriptor( + name="StateMetadataEntry", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.StateMetadataEntry", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="key", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.StateMetadataEntry.key", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.StateMetadataEntry.value", + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=_b("8\001"), + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=706, + serialized_end=758, +) + +_MARKRECOMMENDATIONFAILEDREQUEST = _descriptor.Descriptor( + name="MarkRecommendationFailedRequest", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest", + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name="name", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.name", + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="state_metadata", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.state_metadata", + index=1, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name="etag", + full_name="google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.etag", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_MARKRECOMMENDATIONFAILEDREQUEST_STATEMETADATAENTRY], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto3", + extension_ranges=[], + oneofs=[], + serialized_start=995, + serialized_end=1220, +) + +_LISTRECOMMENDATIONSRESPONSE.fields_by_name[ + "recommendations" +].message_type = ( + google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2._RECOMMENDATION +) +_MARKRECOMMENDATIONCLAIMEDREQUEST_STATEMETADATAENTRY.containing_type = ( + _MARKRECOMMENDATIONCLAIMEDREQUEST +) +_MARKRECOMMENDATIONCLAIMEDREQUEST.fields_by_name[ + "state_metadata" +].message_type = _MARKRECOMMENDATIONCLAIMEDREQUEST_STATEMETADATAENTRY +_MARKRECOMMENDATIONSUCCEEDEDREQUEST_STATEMETADATAENTRY.containing_type = ( + _MARKRECOMMENDATIONSUCCEEDEDREQUEST +) +_MARKRECOMMENDATIONSUCCEEDEDREQUEST.fields_by_name[ + "state_metadata" +].message_type = _MARKRECOMMENDATIONSUCCEEDEDREQUEST_STATEMETADATAENTRY +_MARKRECOMMENDATIONFAILEDREQUEST_STATEMETADATAENTRY.containing_type = ( + _MARKRECOMMENDATIONFAILEDREQUEST +) +_MARKRECOMMENDATIONFAILEDREQUEST.fields_by_name[ + "state_metadata" +].message_type = _MARKRECOMMENDATIONFAILEDREQUEST_STATEMETADATAENTRY +DESCRIPTOR.message_types_by_name[ + "ListRecommendationsRequest" +] = _LISTRECOMMENDATIONSREQUEST +DESCRIPTOR.message_types_by_name[ + "ListRecommendationsResponse" +] = _LISTRECOMMENDATIONSRESPONSE +DESCRIPTOR.message_types_by_name["GetRecommendationRequest"] = _GETRECOMMENDATIONREQUEST +DESCRIPTOR.message_types_by_name[ + "MarkRecommendationClaimedRequest" +] = _MARKRECOMMENDATIONCLAIMEDREQUEST +DESCRIPTOR.message_types_by_name[ + "MarkRecommendationSucceededRequest" +] = _MARKRECOMMENDATIONSUCCEEDEDREQUEST +DESCRIPTOR.message_types_by_name[ + "MarkRecommendationFailedRequest" +] = _MARKRECOMMENDATIONFAILEDREQUEST +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ListRecommendationsRequest = _reflection.GeneratedProtocolMessageType( + "ListRecommendationsRequest", + (_message.Message,), + dict( + DESCRIPTOR=_LISTRECOMMENDATIONSREQUEST, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2", + __doc__="""Request for the ``ListRecommendations`` method. + + + Attributes: + parent: + Required. The container resource on which to execute the + request. Acceptable formats: 1. "projects/[PROJECT\_NUMBER]/l + ocations/[LOCATION]/recommenders/[RECOMMENDER\_ID]", LOCATION + here refers to GCP Locations: + https://cloud.google.com/about/locations/ + page_size: + Optional. The maximum number of results to return from this + request. Non-positive values are ignored. If not specified, + the server will determine the number of results to return. + page_token: + Optional. If present, retrieves the next batch of results from + the preceding call to this method. ``page_token`` must be the + value of ``next_page_token`` from the previous response. The + values of other method parameters must be identical to those + in the previous call. + filter: + Filter expression to restrict the recommendations returned. + Supported filter fields: state\_info.state Eg: + \`state\_info.state:"DISMISSED" or state\_info.state:"FAILED" + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.ListRecommendationsRequest) + ), +) +_sym_db.RegisterMessage(ListRecommendationsRequest) + +ListRecommendationsResponse = _reflection.GeneratedProtocolMessageType( + "ListRecommendationsResponse", + (_message.Message,), + dict( + DESCRIPTOR=_LISTRECOMMENDATIONSRESPONSE, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2", + __doc__="""Response to the ``ListRecommendations`` method. + + + Attributes: + recommendations: + The set of recommendations for the ``parent`` resource. + next_page_token: + A token that can be used to request the next page of results. + This field is empty if there are no additional results. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.ListRecommendationsResponse) + ), +) +_sym_db.RegisterMessage(ListRecommendationsResponse) + +GetRecommendationRequest = _reflection.GeneratedProtocolMessageType( + "GetRecommendationRequest", + (_message.Message,), + dict( + DESCRIPTOR=_GETRECOMMENDATIONREQUEST, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2", + __doc__="""Request to the ``GetRecommendation`` method. + + + Attributes: + name: + Name of the recommendation. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.GetRecommendationRequest) + ), +) +_sym_db.RegisterMessage(GetRecommendationRequest) + +MarkRecommendationClaimedRequest = _reflection.GeneratedProtocolMessageType( + "MarkRecommendationClaimedRequest", + (_message.Message,), + dict( + StateMetadataEntry=_reflection.GeneratedProtocolMessageType( + "StateMetadataEntry", + (_message.Message,), + dict( + DESCRIPTOR=_MARKRECOMMENDATIONCLAIMEDREQUEST_STATEMETADATAENTRY, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2" + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest.StateMetadataEntry) + ), + ), + DESCRIPTOR=_MARKRECOMMENDATIONCLAIMEDREQUEST, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2", + __doc__="""Request for the ``MarkRecommendationClaimed`` Method. + + + Attributes: + name: + Name of the recommendation. + state_metadata: + State properties to include with this state. Overwrites any + existing ``state_metadata``. + etag: + Fingerprint of the Recommendation. Provides optimistic + locking. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.MarkRecommendationClaimedRequest) + ), +) +_sym_db.RegisterMessage(MarkRecommendationClaimedRequest) +_sym_db.RegisterMessage(MarkRecommendationClaimedRequest.StateMetadataEntry) + +MarkRecommendationSucceededRequest = _reflection.GeneratedProtocolMessageType( + "MarkRecommendationSucceededRequest", + (_message.Message,), + dict( + StateMetadataEntry=_reflection.GeneratedProtocolMessageType( + "StateMetadataEntry", + (_message.Message,), + dict( + DESCRIPTOR=_MARKRECOMMENDATIONSUCCEEDEDREQUEST_STATEMETADATAENTRY, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2" + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest.StateMetadataEntry) + ), + ), + DESCRIPTOR=_MARKRECOMMENDATIONSUCCEEDEDREQUEST, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2", + __doc__="""Request for the ``MarkRecommendationSucceeded`` Method. + + + Attributes: + name: + Name of the recommendation. + state_metadata: + State properties to include with this state. Overwrites any + existing ``state_metadata``. + etag: + Fingerprint of the Recommendation. Provides optimistic + locking. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.MarkRecommendationSucceededRequest) + ), +) +_sym_db.RegisterMessage(MarkRecommendationSucceededRequest) +_sym_db.RegisterMessage(MarkRecommendationSucceededRequest.StateMetadataEntry) + +MarkRecommendationFailedRequest = _reflection.GeneratedProtocolMessageType( + "MarkRecommendationFailedRequest", + (_message.Message,), + dict( + StateMetadataEntry=_reflection.GeneratedProtocolMessageType( + "StateMetadataEntry", + (_message.Message,), + dict( + DESCRIPTOR=_MARKRECOMMENDATIONFAILEDREQUEST_STATEMETADATAENTRY, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2" + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest.StateMetadataEntry) + ), + ), + DESCRIPTOR=_MARKRECOMMENDATIONFAILEDREQUEST, + __module__="google.cloud.recommender_v1beta1.proto.recommender_service_pb2", + __doc__="""Request for the ``MarkRecommendationFailed`` Method. + + + Attributes: + name: + Name of the recommendation. + state_metadata: + State properties to include with this state. Overwrites any + existing ``state_metadata``. + etag: + Fingerprint of the Recommendation. Provides optimistic + locking. + """, + # @@protoc_insertion_point(class_scope:google.cloud.recommender.v1beta1.MarkRecommendationFailedRequest) + ), +) +_sym_db.RegisterMessage(MarkRecommendationFailedRequest) +_sym_db.RegisterMessage(MarkRecommendationFailedRequest.StateMetadataEntry) + + +DESCRIPTOR._options = None +_MARKRECOMMENDATIONCLAIMEDREQUEST_STATEMETADATAENTRY._options = None +_MARKRECOMMENDATIONSUCCEEDEDREQUEST_STATEMETADATAENTRY._options = None +_MARKRECOMMENDATIONFAILEDREQUEST_STATEMETADATAENTRY._options = None + +_RECOMMENDER = _descriptor.ServiceDescriptor( + name="Recommender", + full_name="google.cloud.recommender.v1beta1.Recommender", + file=DESCRIPTOR, + index=0, + serialized_options=_b( + "\312A\032recommender.googleapis.com\322A.https://www.googleapis.com/auth/cloud-platform" + ), + serialized_start=1223, + serialized_end=2494, + methods=[ + _descriptor.MethodDescriptor( + name="ListRecommendations", + full_name="google.cloud.recommender.v1beta1.Recommender.ListRecommendations", + index=0, + containing_service=None, + input_type=_LISTRECOMMENDATIONSREQUEST, + output_type=_LISTRECOMMENDATIONSRESPONSE, + serialized_options=_b( + "\202\323\344\223\002I\022G/v1beta1/{parent=projects/*/locations/*/recommenders/*}/recommendations" + ), + ), + _descriptor.MethodDescriptor( + name="GetRecommendation", + full_name="google.cloud.recommender.v1beta1.Recommender.GetRecommendation", + index=1, + containing_service=None, + input_type=_GETRECOMMENDATIONREQUEST, + output_type=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2._RECOMMENDATION, + serialized_options=_b( + "\202\323\344\223\002I\022G/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}" + ), + ), + _descriptor.MethodDescriptor( + name="MarkRecommendationClaimed", + full_name="google.cloud.recommender.v1beta1.Recommender.MarkRecommendationClaimed", + index=2, + containing_service=None, + input_type=_MARKRECOMMENDATIONCLAIMEDREQUEST, + output_type=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2._RECOMMENDATION, + serialized_options=_b( + '\202\323\344\223\002X"S/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markClaimed:\001*' + ), + ), + _descriptor.MethodDescriptor( + name="MarkRecommendationSucceeded", + full_name="google.cloud.recommender.v1beta1.Recommender.MarkRecommendationSucceeded", + index=3, + containing_service=None, + input_type=_MARKRECOMMENDATIONSUCCEEDEDREQUEST, + output_type=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2._RECOMMENDATION, + serialized_options=_b( + '\202\323\344\223\002Z"U/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markSucceeded:\001*' + ), + ), + _descriptor.MethodDescriptor( + name="MarkRecommendationFailed", + full_name="google.cloud.recommender.v1beta1.Recommender.MarkRecommendationFailed", + index=4, + containing_service=None, + input_type=_MARKRECOMMENDATIONFAILEDREQUEST, + output_type=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2._RECOMMENDATION, + serialized_options=_b( + '\202\323\344\223\002W"R/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markFailed:\001*' + ), + ), + ], +) +_sym_db.RegisterServiceDescriptor(_RECOMMENDER) + +DESCRIPTOR.services_by_name["Recommender"] = _RECOMMENDER + +# @@protoc_insertion_point(module_scope) diff --git a/recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2_grpc.py b/recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2_grpc.py new file mode 100644 index 000000000000..24ffe1eb40fb --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/proto/recommender_service_pb2_grpc.py @@ -0,0 +1,155 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +from google.cloud.recommender_v1beta1.proto import ( + recommendation_pb2 as google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2, +) +from google.cloud.recommender_v1beta1.proto import ( + recommender_service_pb2 as google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2, +) + + +class RecommenderStub(object): + """Provides recommendations for cloud customers for various categories like + performance optimization, cost savings, reliability, feature discovery, etc. + These recommendations are generated automatically based on analysis of user + resources, configuration and monitoring metrics. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.ListRecommendations = channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/ListRecommendations", + request_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.ListRecommendationsRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.ListRecommendationsResponse.FromString, + ) + self.GetRecommendation = channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/GetRecommendation", + request_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.GetRecommendationRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.FromString, + ) + self.MarkRecommendationClaimed = channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationClaimed", + request_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.MarkRecommendationClaimedRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.FromString, + ) + self.MarkRecommendationSucceeded = channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationSucceeded", + request_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.MarkRecommendationSucceededRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.FromString, + ) + self.MarkRecommendationFailed = channel.unary_unary( + "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationFailed", + request_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.MarkRecommendationFailedRequest.SerializeToString, + response_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.FromString, + ) + + +class RecommenderServicer(object): + """Provides recommendations for cloud customers for various categories like + performance optimization, cost savings, reliability, feature discovery, etc. + These recommendations are generated automatically based on analysis of user + resources, configuration and monitoring metrics. + """ + + def ListRecommendations(self, request, context): + """Lists recommendations for a Cloud project. Requires the recommender.*.list + IAM permission for the specified recommender. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def GetRecommendation(self, request, context): + """Gets the requested recommendation. Requires the recommender.*.get + IAM permission for the specified recommender. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def MarkRecommendationClaimed(self, request, context): + """Mark the Recommendation State as Claimed. Users can use this method to + indicate to the Recommender API that they are starting to apply the + recommendation themselves. This stops the recommendation content from being + updated. + + MarkRecommendationClaimed can be applied to recommendations in CLAIMED, + SUCCEEDED, FAILED, or ACTIVE state. + + Requires the recommender.*.update IAM permission for the specified + recommender. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def MarkRecommendationSucceeded(self, request, context): + """Mark the Recommendation State as Succeeded. Users can use this method to + indicate to the Recommender API that they have applied the recommendation + themselves, and the operation was successful. This stops the recommendation + content from being updated. + + MarkRecommendationSucceeded can be applied to recommendations in ACTIVE, + CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.*.update IAM permission for the specified + recommender. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + def MarkRecommendationFailed(self, request, context): + """Mark the Recommendation State as Failed. Users can use this method to + indicate to the Recommender API that they have applied the recommendation + themselves, and the operation failed. This stops the recommendation content + from being updated. + + MarkRecommendationFailed can be applied to recommendations in ACTIVE, + CLAIMED, SUCCEEDED, or FAILED state. + + Requires the recommender.*.update IAM permission for the specified + recommender. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details("Method not implemented!") + raise NotImplementedError("Method not implemented!") + + +def add_RecommenderServicer_to_server(servicer, server): + rpc_method_handlers = { + "ListRecommendations": grpc.unary_unary_rpc_method_handler( + servicer.ListRecommendations, + request_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.ListRecommendationsRequest.FromString, + response_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.ListRecommendationsResponse.SerializeToString, + ), + "GetRecommendation": grpc.unary_unary_rpc_method_handler( + servicer.GetRecommendation, + request_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.GetRecommendationRequest.FromString, + response_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.SerializeToString, + ), + "MarkRecommendationClaimed": grpc.unary_unary_rpc_method_handler( + servicer.MarkRecommendationClaimed, + request_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.MarkRecommendationClaimedRequest.FromString, + response_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.SerializeToString, + ), + "MarkRecommendationSucceeded": grpc.unary_unary_rpc_method_handler( + servicer.MarkRecommendationSucceeded, + request_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.MarkRecommendationSucceededRequest.FromString, + response_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.SerializeToString, + ), + "MarkRecommendationFailed": grpc.unary_unary_rpc_method_handler( + servicer.MarkRecommendationFailed, + request_deserializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommender__service__pb2.MarkRecommendationFailedRequest.FromString, + response_serializer=google_dot_cloud_dot_recommender__v1beta1_dot_proto_dot_recommendation__pb2.Recommendation.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + "google.cloud.recommender.v1beta1.Recommender", rpc_method_handlers + ) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/recommender/google/cloud/recommender_v1beta1/py.typed b/recommender/google/cloud/recommender_v1beta1/py.typed deleted file mode 100644 index f9105be894e2..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/py.typed +++ /dev/null @@ -1,2 +0,0 @@ -# Marker file for PEP 561. -# The google-cloud-recommender package uses inline types. diff --git a/recommender/google/cloud/recommender_v1beta1/services/__init__.py b/recommender/google/cloud/recommender_v1beta1/services/__init__.py deleted file mode 100644 index 40a96afc6ff0..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py deleted file mode 100644 index e0016832d0fb..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/recommender/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -from .client import Recommender - -__all__ = ("Recommender",) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/client.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/client.py deleted file mode 100644 index 92316afb4752..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/recommender/client.py +++ /dev/null @@ -1,395 +0,0 @@ -# -*- coding: utf-8 -*- -from collections import OrderedDict -from typing import Dict, Sequence, Tuple, Type, Union -import pkg_resources - -from google.api_core import exceptions # type: ignore -from google.api_core import gapic_v1 # type: ignore -from google.api_core import retry as retries # type: ignore -from google.auth import credentials # type: ignore - -from google.cloud.recommender_v1beta1.services.recommender import pagers -from google.cloud.recommender_v1beta1.types import recommendation -from google.cloud.recommender_v1beta1.types import recommender_service - -from .transports.base import RecommenderTransport -from .transports.grpc import RecommenderGrpcTransport - - -class RecommenderMeta(type): - """Metaclass for the Recommender client. - - This provides class-level methods for building and retrieving - support objects (e.g. transport) without polluting the client instance - objects. - """ - - _transport_registry = OrderedDict() # type: Dict[str, Type[RecommenderTransport]] - _transport_registry["grpc"] = RecommenderGrpcTransport - - def get_transport_class(cls, label: str = None) -> Type[RecommenderTransport]: - """Return an appropriate transport class. - - Args: - label: The name of the desired transport. If none is - provided, then the first transport in the registry is used. - - Returns: - The transport class to use. - """ - # If a specific transport is requested, return that one. - if label: - return cls._transport_registry[label] - - # No transport is requested; return the default (that is, the first one - # in the dictionary). - return next(iter(cls._transport_registry.values())) - - -class Recommender(metaclass=RecommenderMeta): - """Provides recommendations for cloud customers for various - categories like performance optimization, cost savings, - reliability, feature discovery, etc. These recommendations are - generated automatically based on analysis of user resources, - configuration and monitoring metrics. - """ - - def __init__( - self, - *, - host: str = "recommender.googleapis.com", - credentials: credentials.Credentials = None, - transport: Union[str, RecommenderTransport] = None - ) -> None: - """Instantiate the recommender. - - Args: - host (Optional[str]): The hostname to connect to. - credentials (Optional[google.auth.credentials.Credentials]): The - authorization credentials to attach to requests. These - credentials identify the application to the service; if none - are specified, the client will attempt to ascertain the - credentials from the environment. - transport (Union[str, ~.RecommenderTransport]): The - transport to use. If set to None, a transport is chosen - automatically. - """ - # Save or instantiate the transport. - # Ordinarily, we provide the transport, but allowing a custom transport - # instance provides an extensibility point for unusual situations. - if isinstance(transport, RecommenderTransport): - if credentials: - raise ValueError( - "When providing a transport instance, " - "provide its credentials directly." - ) - self._transport = transport - else: - Transport = type(self).get_transport_class(transport) - self._transport = Transport(credentials=credentials, host=host) - - def list_recommendations( - self, - request: recommender_service.ListRecommendationsRequest = None, - *, - retry: retries.Retry = gapic_v1.method.DEFAULT, - timeout: float = None, - metadata: Sequence[Tuple[str, str]] = () - ) -> pagers.ListRecommendationsPager: - r"""Lists recommendations for a Cloud project. Requires the - recommender.*.list IAM permission for the specified recommender. - - Args: - request (:class:`~.recommender_service.ListRecommendationsRequest`): - The request object. Request for the - `ListRecommendations` method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, - should be retried. - timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. - - Returns: - ~.pagers.ListRecommendationsPager: - Response to the ``ListRecommendations`` method. - - Iterating over this object will yield results and - resolve additional pages automatically. - - """ - # Create or coerce a protobuf request object. - request = recommender_service.ListRecommendationsRequest(request) - - # Wrap the RPC method; this adds retry and timeout information, - # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.list_recommendations, - default_retry=retries.Retry( - predicate=retries.if_exception_type( - exceptions.Aborted, - exceptions.ServiceUnavailable, - exceptions.Unknown, - ) - ), - default_timeout=None, - client_info=_client_info, - ) - - # Certain fields should be provided within the metadata header; - # add these here. - metadata = tuple(metadata) + ( - gapic_v1.routing_header.to_grpc_metadata((("parent", request.parent),)), - ) - - # Send the request. - response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) - - # This method is paged; wrap the response in a pager, which provides - # an `__iter__` convenience method. - response = pagers.ListRecommendationsPager( - method=rpc, request=request, response=response - ) - - # Done; return the response. - return response - - def get_recommendation( - self, - request: recommender_service.GetRecommendationRequest = None, - *, - retry: retries.Retry = gapic_v1.method.DEFAULT, - timeout: float = None, - metadata: Sequence[Tuple[str, str]] = () - ) -> recommendation.Recommendation: - r"""Gets the requested recommendation. Requires the - recommender.*.get IAM permission for the specified recommender. - - Args: - request (:class:`~.recommender_service.GetRecommendationRequest`): - The request object. Request to the `GetRecommendation` - method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, - should be retried. - timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. - - Returns: - ~.recommendation.Recommendation: - A recommendation along with a - suggested action. E.g., a rightsizing - recommendation for an underutilized VM, - IAM role recommendations, etc - - """ - # Create or coerce a protobuf request object. - request = recommender_service.GetRecommendationRequest(request) - - # Wrap the RPC method; this adds retry and timeout information, - # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.get_recommendation, - default_retry=retries.Retry( - predicate=retries.if_exception_type( - exceptions.Aborted, - exceptions.ServiceUnavailable, - exceptions.Unknown, - ) - ), - default_timeout=None, - client_info=_client_info, - ) - - # Certain fields should be provided within the metadata header; - # add these here. - metadata = tuple(metadata) + ( - gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), - ) - - # Send the request. - response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) - - # Done; return the response. - return response - - def mark_recommendation_claimed( - self, - request: recommender_service.MarkRecommendationClaimedRequest = None, - *, - retry: retries.Retry = gapic_v1.method.DEFAULT, - timeout: float = None, - metadata: Sequence[Tuple[str, str]] = () - ) -> recommendation.Recommendation: - r"""Mark the Recommendation State as Claimed. Users can use this - method to indicate to the Recommender API that they are starting - to apply the recommendation themselves. This stops the - recommendation content from being updated. - - MarkRecommendationClaimed can be applied to recommendations in - CLAIMED, SUCCEEDED, FAILED, or ACTIVE state. - - Requires the recommender.*.update IAM permission for the - specified recommender. - - Args: - request (:class:`~.recommender_service.MarkRecommendationClaimedRequest`): - The request object. Request for the - `MarkRecommendationClaimed` Method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, - should be retried. - timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. - - Returns: - ~.recommendation.Recommendation: - A recommendation along with a - suggested action. E.g., a rightsizing - recommendation for an underutilized VM, - IAM role recommendations, etc - - """ - # Create or coerce a protobuf request object. - request = recommender_service.MarkRecommendationClaimedRequest(request) - - # Wrap the RPC method; this adds retry and timeout information, - # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.mark_recommendation_claimed, - default_retry=retries.Retry( - predicate=retries.if_exception_type(exceptions.ServiceUnavailable) - ), - default_timeout=None, - client_info=_client_info, - ) - - # Send the request. - response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) - - # Done; return the response. - return response - - def mark_recommendation_succeeded( - self, - request: recommender_service.MarkRecommendationSucceededRequest = None, - *, - retry: retries.Retry = gapic_v1.method.DEFAULT, - timeout: float = None, - metadata: Sequence[Tuple[str, str]] = () - ) -> recommendation.Recommendation: - r"""Mark the Recommendation State as Succeeded. Users can use this - method to indicate to the Recommender API that they have applied - the recommendation themselves, and the operation was successful. - This stops the recommendation content from being updated. - - MarkRecommendationSucceeded can be applied to recommendations in - ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. - - Requires the recommender.*.update IAM permission for the - specified recommender. - - Args: - request (:class:`~.recommender_service.MarkRecommendationSucceededRequest`): - The request object. Request for the - `MarkRecommendationSucceeded` Method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, - should be retried. - timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. - - Returns: - ~.recommendation.Recommendation: - A recommendation along with a - suggested action. E.g., a rightsizing - recommendation for an underutilized VM, - IAM role recommendations, etc - - """ - # Create or coerce a protobuf request object. - request = recommender_service.MarkRecommendationSucceededRequest(request) - - # Wrap the RPC method; this adds retry and timeout information, - # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.mark_recommendation_succeeded, - default_retry=retries.Retry( - predicate=retries.if_exception_type(exceptions.ServiceUnavailable) - ), - default_timeout=None, - client_info=_client_info, - ) - - # Send the request. - response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) - - # Done; return the response. - return response - - def mark_recommendation_failed( - self, - request: recommender_service.MarkRecommendationFailedRequest = None, - *, - retry: retries.Retry = gapic_v1.method.DEFAULT, - timeout: float = None, - metadata: Sequence[Tuple[str, str]] = () - ) -> recommendation.Recommendation: - r"""Mark the Recommendation State as Failed. Users can use this - method to indicate to the Recommender API that they have applied - the recommendation themselves, and the operation failed. This - stops the recommendation content from being updated. - - MarkRecommendationFailed can be applied to recommendations in - ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. - - Requires the recommender.*.update IAM permission for the - specified recommender. - - Args: - request (:class:`~.recommender_service.MarkRecommendationFailedRequest`): - The request object. Request for the - `MarkRecommendationFailed` Method. - retry (google.api_core.retry.Retry): Designation of what errors, if any, - should be retried. - timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. - - Returns: - ~.recommendation.Recommendation: - A recommendation along with a - suggested action. E.g., a rightsizing - recommendation for an underutilized VM, - IAM role recommendations, etc - - """ - # Create or coerce a protobuf request object. - request = recommender_service.MarkRecommendationFailedRequest(request) - - # Wrap the RPC method; this adds retry and timeout information, - # and friendly error handling. - rpc = gapic_v1.method.wrap_method( - self._transport.mark_recommendation_failed, - default_retry=retries.Retry( - predicate=retries.if_exception_type(exceptions.ServiceUnavailable) - ), - default_timeout=None, - client_info=_client_info, - ) - - # Send the request. - response = rpc(request, retry=retry, timeout=timeout, metadata=metadata) - - # Done; return the response. - return response - - -try: - _client_info = gapic_v1.client_info.ClientInfo( - gapic_version=pkg_resources.get_distribution("google-cloud-recommender").version - ) -except pkg_resources.DistributionNotFound: - _client_info = gapic_v1.client_info.ClientInfo() - - -__all__ = ("Recommender",) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py deleted file mode 100644 index 153ecb198b15..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/recommender/pagers.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import Any, Callable, Iterable - -from google.cloud.recommender_v1beta1.types import recommendation -from google.cloud.recommender_v1beta1.types import recommender_service - - -class ListRecommendationsPager: - """A pager for iterating through ``list_recommendations`` requests. - - This class thinly wraps an initial - :class:`~.recommender_service.ListRecommendationsResponse` object, and - provides an ``__iter__`` method to iterate through its - ``recommendations`` field. - - If there are more pages, the ``__iter__`` method will make additional - ``ListRecommendations`` requests and continue to iterate - through the ``recommendations`` field on the - corresponding responses. - - All the usual :class:`~.recommender_service.ListRecommendationsResponse` - attributes are available on the pager. If multiple requests are made, only - the most recent response is retained, and thus used for attribute lookup. - """ - - def __init__( - self, - method: Callable[ - [recommender_service.ListRecommendationsRequest], - recommender_service.ListRecommendationsResponse, - ], - request: recommender_service.ListRecommendationsRequest, - response: recommender_service.ListRecommendationsResponse, - ): - """Instantiate the pager. - - Args: - method (Callable): The method that was originally called, and - which instantiated this pager. - request (:class:`~.recommender_service.ListRecommendationsRequest`): - The initial request object. - response (:class:`~.recommender_service.ListRecommendationsResponse`): - The initial response object. - """ - self._method = method - self._request = recommender_service.ListRecommendationsRequest(request) - self._response = response - - def __getattr__(self, name: str) -> Any: - return getattr(self._response, name) - - def __iter__(self) -> Iterable[recommendation.Recommendation]: - while True: - # Iterate through the results on this response. - for result in self._response.recommendations: - yield result - - # Sanity check: Is this the last page? If so, we are done. - if not self._response.next_page_token: - break - - # Get the next page. - self._request.page_token = self._response.next_page_token - self._response = self._method(self._request) - - def __repr__(self) -> str: - return "{0}<{1!r}>".format(self.__class__.__name__, self._response) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py deleted file mode 100644 index ccda47244c80..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- -from collections import OrderedDict -from typing import Dict, Type - -from .base import RecommenderTransport -from .grpc import RecommenderGrpcTransport - - -# Compile a registry of transports. -_transport_registry = OrderedDict() # type: Dict[str, Type[RecommenderTransport]] -_transport_registry["grpc"] = RecommenderGrpcTransport - - -__all__ = ("RecommenderTransport", "RecommenderGrpcTransport") diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py deleted file mode 100644 index da92f77fed38..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/base.py +++ /dev/null @@ -1,91 +0,0 @@ -# -*- coding: utf-8 -*- -import abc -import typing - -from google import auth -from google.auth import credentials # type: ignore - -from google.cloud.recommender_v1beta1.types import recommendation -from google.cloud.recommender_v1beta1.types import recommender_service - - -class RecommenderTransport(metaclass=abc.ABCMeta): - """Abstract transport class for Recommender.""" - - AUTH_SCOPES = ("https://www.googleapis.com/auth/cloud-platform",) - - def __init__( - self, - *, - host: str = "recommender.googleapis.com", - credentials: credentials.Credentials = None - ) -> None: - """Instantiate the transport. - - Args: - host (Optional[str]): The hostname to connect to. - credentials (Optional[google.auth.credentials.Credentials]): The - authorization credentials to attach to requests. These - credentials identify the application to the service; if none - are specified, the client will attempt to ascertain the - credentials from the environment. - """ - # Save the hostname. Default to port 443 (HTTPS) if none is specified. - if ":" not in host: - host += ":443" - self._host = host - - # If no credentials are provided, then determine the appropriate - # defaults. - if credentials is None: - credentials, _ = auth.default(scopes=self.AUTH_SCOPES) - - # Save the credentials. - self._credentials = credentials - - @property - def list_recommendations( - self - ) -> typing.Callable[ - [recommender_service.ListRecommendationsRequest], - recommender_service.ListRecommendationsResponse, - ]: - raise NotImplementedError - - @property - def get_recommendation( - self - ) -> typing.Callable[ - [recommender_service.GetRecommendationRequest], recommendation.Recommendation - ]: - raise NotImplementedError - - @property - def mark_recommendation_claimed( - self - ) -> typing.Callable[ - [recommender_service.MarkRecommendationClaimedRequest], - recommendation.Recommendation, - ]: - raise NotImplementedError - - @property - def mark_recommendation_succeeded( - self - ) -> typing.Callable[ - [recommender_service.MarkRecommendationSucceededRequest], - recommendation.Recommendation, - ]: - raise NotImplementedError - - @property - def mark_recommendation_failed( - self - ) -> typing.Callable[ - [recommender_service.MarkRecommendationFailedRequest], - recommendation.Recommendation, - ]: - raise NotImplementedError - - -__all__ = ("RecommenderTransport",) diff --git a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py b/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py deleted file mode 100644 index f9c449266a2e..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/services/recommender/transports/grpc.py +++ /dev/null @@ -1,258 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import Callable, Dict - -from google.api_core import grpc_helpers # type: ignore -from google.auth import credentials # type: ignore - -import grpc # type: ignore - -from google.cloud.recommender_v1beta1.types import recommendation -from google.cloud.recommender_v1beta1.types import recommender_service - -from .base import RecommenderTransport - - -class RecommenderGrpcTransport(RecommenderTransport): - """gRPC backend transport for Recommender. - - Provides recommendations for cloud customers for various - categories like performance optimization, cost savings, - reliability, feature discovery, etc. These recommendations are - generated automatically based on analysis of user resources, - configuration and monitoring metrics. - - This class defines the same methods as the primary client, so the - primary client can load the underlying transport implementation - and call it. - - It sends protocol buffers over the wire using gRPC (which is built on - top of HTTP/2); the ``grpcio`` package must be installed. - """ - - def __init__( - self, - *, - host: str = "recommender.googleapis.com", - credentials: credentials.Credentials = None, - channel: grpc.Channel = None - ) -> None: - """Instantiate the transport. - - Args: - host (Optional[str]): The hostname to connect to. - credentials (Optional[google.auth.credentials.Credentials]): The - authorization credentials to attach to requests. These - credentials identify the application to the service; if none - are specified, the client will attempt to ascertain the - credentials from the environment. - This argument is ignored if ``channel`` is provided. - channel (Optional[grpc.Channel]): A ``Channel`` instance through - which to make calls. - """ - # Sanity check: Ensure that channel and credentials are not both - # provided. - if channel: - credentials = False - - # Run the base constructor. - super().__init__(host=host, credentials=credentials) - self._stubs = {} # type: Dict[str, Callable] - - # If a channel was explicitly provided, set it. - if channel: - self._grpc_channel = channel - - @property - def grpc_channel(self) -> grpc.Channel: - """Create the channel designed to connect to this service. - - This property caches on the instance; repeated calls return - the same channel. - """ - # Sanity check: Only create a new channel if we do not already - # have one. - if not hasattr(self, "_grpc_channel"): - self._grpc_channel = grpc_helpers.create_channel( - self._host, credentials=self._credentials, scopes=self.AUTH_SCOPES - ) - - # Return the channel from cache. - return self._grpc_channel - - @property - def list_recommendations( - self - ) -> Callable[ - [recommender_service.ListRecommendationsRequest], - recommender_service.ListRecommendationsResponse, - ]: - r"""Return a callable for the list recommendations method over gRPC. - - Lists recommendations for a Cloud project. Requires the - recommender.*.list IAM permission for the specified recommender. - - Returns: - Callable[[~.ListRecommendationsRequest], - ~.ListRecommendationsResponse]: - A function that, when called, will call the underlying RPC - on the server. - """ - # Generate a "stub function" on-the-fly which will actually make - # the request. - # gRPC handles serialization and deserialization, so we just need - # to pass in the functions for each. - if "list_recommendations" not in self._stubs: - self._stubs["list_recommendations"] = self.grpc_channel.unary_unary( - "/google.cloud.recommender.v1beta1.Recommender/ListRecommendations", - request_serializer=recommender_service.ListRecommendationsRequest.serialize, - response_deserializer=recommender_service.ListRecommendationsResponse.deserialize, - ) - return self._stubs["list_recommendations"] - - @property - def get_recommendation( - self - ) -> Callable[ - [recommender_service.GetRecommendationRequest], recommendation.Recommendation - ]: - r"""Return a callable for the get recommendation method over gRPC. - - Gets the requested recommendation. Requires the - recommender.*.get IAM permission for the specified recommender. - - Returns: - Callable[[~.GetRecommendationRequest], - ~.Recommendation]: - A function that, when called, will call the underlying RPC - on the server. - """ - # Generate a "stub function" on-the-fly which will actually make - # the request. - # gRPC handles serialization and deserialization, so we just need - # to pass in the functions for each. - if "get_recommendation" not in self._stubs: - self._stubs["get_recommendation"] = self.grpc_channel.unary_unary( - "/google.cloud.recommender.v1beta1.Recommender/GetRecommendation", - request_serializer=recommender_service.GetRecommendationRequest.serialize, - response_deserializer=recommendation.Recommendation.deserialize, - ) - return self._stubs["get_recommendation"] - - @property - def mark_recommendation_claimed( - self - ) -> Callable[ - [recommender_service.MarkRecommendationClaimedRequest], - recommendation.Recommendation, - ]: - r"""Return a callable for the mark recommendation claimed method over gRPC. - - Mark the Recommendation State as Claimed. Users can use this - method to indicate to the Recommender API that they are starting - to apply the recommendation themselves. This stops the - recommendation content from being updated. - - MarkRecommendationClaimed can be applied to recommendations in - CLAIMED, SUCCEEDED, FAILED, or ACTIVE state. - - Requires the recommender.*.update IAM permission for the - specified recommender. - - Returns: - Callable[[~.MarkRecommendationClaimedRequest], - ~.Recommendation]: - A function that, when called, will call the underlying RPC - on the server. - """ - # Generate a "stub function" on-the-fly which will actually make - # the request. - # gRPC handles serialization and deserialization, so we just need - # to pass in the functions for each. - if "mark_recommendation_claimed" not in self._stubs: - self._stubs["mark_recommendation_claimed"] = self.grpc_channel.unary_unary( - "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationClaimed", - request_serializer=recommender_service.MarkRecommendationClaimedRequest.serialize, - response_deserializer=recommendation.Recommendation.deserialize, - ) - return self._stubs["mark_recommendation_claimed"] - - @property - def mark_recommendation_succeeded( - self - ) -> Callable[ - [recommender_service.MarkRecommendationSucceededRequest], - recommendation.Recommendation, - ]: - r"""Return a callable for the mark recommendation succeeded method over gRPC. - - Mark the Recommendation State as Succeeded. Users can use this - method to indicate to the Recommender API that they have applied - the recommendation themselves, and the operation was successful. - This stops the recommendation content from being updated. - - MarkRecommendationSucceeded can be applied to recommendations in - ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. - - Requires the recommender.*.update IAM permission for the - specified recommender. - - Returns: - Callable[[~.MarkRecommendationSucceededRequest], - ~.Recommendation]: - A function that, when called, will call the underlying RPC - on the server. - """ - # Generate a "stub function" on-the-fly which will actually make - # the request. - # gRPC handles serialization and deserialization, so we just need - # to pass in the functions for each. - if "mark_recommendation_succeeded" not in self._stubs: - self._stubs[ - "mark_recommendation_succeeded" - ] = self.grpc_channel.unary_unary( - "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationSucceeded", - request_serializer=recommender_service.MarkRecommendationSucceededRequest.serialize, - response_deserializer=recommendation.Recommendation.deserialize, - ) - return self._stubs["mark_recommendation_succeeded"] - - @property - def mark_recommendation_failed( - self - ) -> Callable[ - [recommender_service.MarkRecommendationFailedRequest], - recommendation.Recommendation, - ]: - r"""Return a callable for the mark recommendation failed method over gRPC. - - Mark the Recommendation State as Failed. Users can use this - method to indicate to the Recommender API that they have applied - the recommendation themselves, and the operation failed. This - stops the recommendation content from being updated. - - MarkRecommendationFailed can be applied to recommendations in - ACTIVE, CLAIMED, SUCCEEDED, or FAILED state. - - Requires the recommender.*.update IAM permission for the - specified recommender. - - Returns: - Callable[[~.MarkRecommendationFailedRequest], - ~.Recommendation]: - A function that, when called, will call the underlying RPC - on the server. - """ - # Generate a "stub function" on-the-fly which will actually make - # the request. - # gRPC handles serialization and deserialization, so we just need - # to pass in the functions for each. - if "mark_recommendation_failed" not in self._stubs: - self._stubs["mark_recommendation_failed"] = self.grpc_channel.unary_unary( - "/google.cloud.recommender.v1beta1.Recommender/MarkRecommendationFailed", - request_serializer=recommender_service.MarkRecommendationFailedRequest.serialize, - response_deserializer=recommendation.Recommendation.deserialize, - ) - return self._stubs["mark_recommendation_failed"] - - -__all__ = ("RecommenderGrpcTransport",) diff --git a/recommender/google/cloud/recommender_v1beta1/types.py b/recommender/google/cloud/recommender_v1beta1/types.py new file mode 100644 index 000000000000..205bae43ea9c --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/types.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from __future__ import absolute_import +import sys + +from google.api_core.protobuf_helpers import get_messages + +from google.cloud.recommender_v1beta1.proto import recommendation_pb2 +from google.cloud.recommender_v1beta1.proto import recommender_service_pb2 +from google.protobuf import duration_pb2 +from google.protobuf import struct_pb2 +from google.protobuf import timestamp_pb2 +from google.type import money_pb2 + + +_shared_modules = [duration_pb2, struct_pb2, timestamp_pb2, money_pb2] + +_local_modules = [recommendation_pb2, recommender_service_pb2] + +names = [] + +for module in _shared_modules: # pragma: NO COVER + for name, message in get_messages(module).items(): + setattr(sys.modules[__name__], name, message) + names.append(name) +for module in _local_modules: + for name, message in get_messages(module).items(): + message.__module__ = "google.cloud.recommender_v1beta1.types" + setattr(sys.modules[__name__], name, message) + names.append(name) + + +__all__ = tuple(sorted(names)) diff --git a/recommender/google/cloud/recommender_v1beta1/types/recommendation.py b/recommender/google/cloud/recommender_v1beta1/types/recommendation.py deleted file mode 100644 index bc55b7f9816e..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/types/recommendation.py +++ /dev/null @@ -1,275 +0,0 @@ -# -*- coding: utf-8 -*- -import proto # type: ignore - - -from google.protobuf import duration_pb2 as gp_duration # type: ignore -from google.protobuf import struct_pb2 as struct # type: ignore -from google.protobuf import timestamp_pb2 as timestamp # type: ignore -from google.type import money_pb2 as money # type: ignore - - -__protobuf__ = proto.module( - package="google.cloud.recommender.v1beta1", - manifest={ - "Recommendation", - "RecommendationContent", - "OperationGroup", - "Operation", - "CostProjection", - "Impact", - "RecommendationStateInfo", - }, -) - - -class Recommendation(proto.Message): - r"""A recommendation along with a suggested action. E.g., a - rightsizing recommendation for an underutilized VM, IAM role - recommendations, etc - - Attributes: - name (str): - Name of recommendation. - - A project recommendation is represented as - projects/[PROJECT_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER_ID]/recommendations/[RECOMMENDATION_ID] - description (str): - Free-form human readable summary in English. - The maximum length is 500 characters. - recommender_subtype (str): - Contains an identifier for a subtype of recommendations - produced for the same recommender. Subtype is a function of - content and impact, meaning a new subtype will be added when - either content or primary impact category changes. - - Examples: For recommender = - "google.iam.policy.RoleRecommender", recommender_subtype can - be one of "REMOVE_ROLE"/"REPLACE_ROLE". - last_refresh_time (~.timestamp.Timestamp): - Last time this recommendation was refreshed - by the system that created it in the first - place. - primary_impact (~.recommendation.Impact): - The primary impact that this recommendation - can have while trying to optimize for one - category. - additional_impact (Sequence[~.recommendation.Impact]): - Optional set of additional impact that this - recommendation may have when trying to optimize - for the primary category. These may be positive - or negative. - content (~.recommendation.RecommendationContent): - Content of the recommendation describing - recommended changes to resources. - state_info (~.recommendation.RecommendationStateInfo): - Information for state. Contains state and - metadata. - etag (str): - Fingerprint of the Recommendation. Provides - optimistic locking when updating states. - """ - name = proto.Field(proto.STRING, number=1) - description = proto.Field(proto.STRING, number=2) - recommender_subtype = proto.Field(proto.STRING, number=12) - last_refresh_time = proto.Field( - proto.MESSAGE, number=4, message=timestamp.Timestamp - ) - primary_impact = proto.Field(proto.MESSAGE, number=5, message="Impact") - additional_impact = proto.RepeatedField(proto.MESSAGE, number=6, message="Impact") - content = proto.Field(proto.MESSAGE, number=7, message="RecommendationContent") - state_info = proto.Field( - proto.MESSAGE, number=10, message="RecommendationStateInfo" - ) - etag = proto.Field(proto.STRING, number=11) - - -class RecommendationContent(proto.Message): - r"""Contains what resources are changing and how they are - changing. - - Attributes: - operation_groups (Sequence[~.recommendation.OperationGroup]): - Operations to one or more Google Cloud - resources grouped in such a way that, all - operations within one group are expected to be - performed atomically and in an order. - """ - operation_groups = proto.RepeatedField( - proto.MESSAGE, number=2, message="OperationGroup" - ) - - -class OperationGroup(proto.Message): - r"""Group of operations that need to be performed atomically. - - Attributes: - operations (Sequence[~.recommendation.Operation]): - List of operations across one or more - resources that belong to this group. Loosely - based on RFC6902 and should be performed in the - order they appear. - """ - operations = proto.RepeatedField(proto.MESSAGE, number=1, message="Operation") - - -class Operation(proto.Message): - r"""Contains an operation for a resource inspired by the JSON-PATCH - format with support for: - - - Custom filters for describing partial array patch. - - Extended path values for describing nested arrays. - - Custom fields for describing the resource for which the operation - is being described. - - Allows extension to custom operations not natively supported by - RFC6902. See https://tools.ietf.org/html/rfc6902 for details on - the original RFC. - - Attributes: - action (str): - Type of this operation. Contains one of - 'and', 'remove', 'replace', 'move', 'copy', - 'test' and custom operations. This field is - case-insensitive and always populated. - resource_type (str): - Type of GCP resource being modified/tested. - This field is always populated. Example: - cloudresourcemanager.googleapis.com/Project, - compute.googleapis.com/Instance - resource (str): - Contains the fully qualified resource name. - This field is always populated. ex: - //cloudresourcemanager.googleapis.com/projects/foo. - path (str): - Path to the target field being operated on. - If the operation is at the resource level, then - path should be "/". This field is always - populated. - source_resource (str): - Can be set with action 'copy' to copy resource configuration - across different resources of the same type. Example: A - resource clone can be done via action = 'copy', path = "/", - from = "/", source_resource = and resource_name = . This - field is empty for all other values of ``action``. - source_path (str): - Can be set with action 'copy' or 'move' to indicate the - source field within resource or source_resource, ignored if - provided for other operation types. - value (~.struct.Value): - Value for the ``path`` field. Set if action is - 'add'/'replace'/'test'. - path_filters (Sequence[~.recommendation.Operation.PathFiltersEntry]): - Set of filters to apply if ``path`` refers to array elements - or nested array elements in order to narrow down to a single - unique element that is being tested/modified. Note that this - is intended to be an exact match per filter. ``Example: { - "/versions/*/name" : "it-123" - "/versions/*/targetSize/percent": 20 }`` ``Example: { - "/bindings/*/role": "roles/admin" "/bindings/*/condition" : - null }`` ``Example: { "/bindings/*/role": "roles/admin" - "/bindings/*/members/*" : ["x@google.com", "y@google.com"] }`` - """ - - class PathFiltersEntry(proto.Message): - r""" - - Attributes: - key (str): - - value (~.struct.Value): - - """ - key = proto.Field(proto.STRING, number=1) - value = proto.Field(proto.MESSAGE, number=2, message=struct.Value) - - action = proto.Field(proto.STRING, number=1) - resource_type = proto.Field(proto.STRING, number=2) - resource = proto.Field(proto.STRING, number=3) - path = proto.Field(proto.STRING, number=4) - source_resource = proto.Field(proto.STRING, number=5) - source_path = proto.Field(proto.STRING, number=6) - value = proto.Field(proto.MESSAGE, number=7, message=struct.Value) - path_filters = proto.RepeatedField( - proto.MESSAGE, number=8, message=PathFiltersEntry - ) - - -class CostProjection(proto.Message): - r"""Contains metadata about how much money a recommendation can - save or incur. - - Attributes: - cost (~.money.Money): - An approximate projection on amount saved or - amount incurred. Negative cost units indicate - cost savings and positive cost units indicate - increase. See google.type.Money documentation - for positive/negative units. - duration (~.gp_duration.Duration): - Duration for which this cost applies. - """ - cost = proto.Field(proto.MESSAGE, number=1, message=money.Money) - duration = proto.Field(proto.MESSAGE, number=2, message=gp_duration.Duration) - - -class Impact(proto.Message): - r"""Contains the impact a recommendation can have for a given - category. - - Attributes: - category (~.recommendation.Impact.Category): - Category that is being targeted. - cost_projection (~.recommendation.CostProjection): - Use with CategoryType.COST - """ - - class Category(proto.Enum): - r"""The category of the impact.""" - CATEGORY_UNSPECIFIED = 0 - COST = 1 - SECURITY = 2 - PERFORMANCE = 3 - - category = proto.Field(proto.ENUM, number=1, enum=Category) - cost_projection = proto.Field(proto.MESSAGE, number=100, message=CostProjection) - - -class RecommendationStateInfo(proto.Message): - r"""Information for state. Contains state and metadata. - - Attributes: - state (~.recommendation.RecommendationStateInfo.State): - The state of the recommendation, Eg ACTIVE, - SUCCEEDED, FAILED. - state_metadata (Sequence[~.recommendation.RecommendationStateInfo.StateMetadataEntry]): - A map of metadata for the state, provided by - user or automations systems. - """ - - class State(proto.Enum): - r"""Represents Recommendation State""" - STATE_UNSPECIFIED = 0 - ACTIVE = 1 - CLAIMED = 6 - SUCCEEDED = 3 - FAILED = 4 - DISMISSED = 5 - - class StateMetadataEntry(proto.Message): - r""" - - Attributes: - key (str): - - value (str): - - """ - key = proto.Field(proto.STRING, number=1) - value = proto.Field(proto.STRING, number=2) - - state = proto.Field(proto.ENUM, number=1, enum=State) - state_metadata = proto.RepeatedField( - proto.MESSAGE, number=2, message=StateMetadataEntry - ) - - -__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/recommender/google/cloud/recommender_v1beta1/types/recommender_service.py b/recommender/google/cloud/recommender_v1beta1/types/recommender_service.py deleted file mode 100644 index af5aa187e26f..000000000000 --- a/recommender/google/cloud/recommender_v1beta1/types/recommender_service.py +++ /dev/null @@ -1,183 +0,0 @@ -# -*- coding: utf-8 -*- -import proto # type: ignore - - -from google.cloud.recommender_v1beta1.types import recommendation - - -__protobuf__ = proto.module( - package="google.cloud.recommender.v1beta1", - manifest={ - "ListRecommendationsRequest", - "ListRecommendationsResponse", - "GetRecommendationRequest", - "MarkRecommendationClaimedRequest", - "MarkRecommendationSucceededRequest", - "MarkRecommendationFailedRequest", - }, -) - - -class ListRecommendationsRequest(proto.Message): - r"""Request for the ``ListRecommendations`` method. - - Attributes: - parent (str): - Required. The container resource on which to execute the - request. Acceptable formats: - - 1. - - "projects/[PROJECT_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER_ID]", - - LOCATION here refers to GCP Locations: - https://cloud.google.com/about/locations/ - page_size (int): - Optional. The maximum number of results to - return from this request. Non-positive values - are ignored. If not specified, the server will - determine the number of results to return. - page_token (str): - Optional. If present, retrieves the next batch of results - from the preceding call to this method. ``page_token`` must - be the value of ``next_page_token`` from the previous - response. The values of other method parameters must be - identical to those in the previous call. - filter (str): - Filter expression to restrict the recommendations returned. - Supported filter fields: state_info.state Eg: - \`state_info.state:"DISMISSED" or state_info.state:"FAILED". - """ - parent = proto.Field(proto.STRING, number=1) - page_size = proto.Field(proto.INT32, number=2) - page_token = proto.Field(proto.STRING, number=3) - filter = proto.Field(proto.STRING, number=5) - - -class ListRecommendationsResponse(proto.Message): - r"""Response to the ``ListRecommendations`` method. - - Attributes: - recommendations (Sequence[~.recommendation.Recommendation]): - The set of recommendations for the ``parent`` resource. - next_page_token (str): - A token that can be used to request the next - page of results. This field is empty if there - are no additional results. - """ - recommendations = proto.RepeatedField( - proto.MESSAGE, number=1, message=recommendation.Recommendation - ) - next_page_token = proto.Field(proto.STRING, number=2) - - -class GetRecommendationRequest(proto.Message): - r"""Request to the ``GetRecommendation`` method. - - Attributes: - name (str): - Name of the recommendation. - """ - name = proto.Field(proto.STRING, number=1) - - -class MarkRecommendationClaimedRequest(proto.Message): - r"""Request for the ``MarkRecommendationClaimed`` Method. - - Attributes: - name (str): - Name of the recommendation. - state_metadata (Sequence[~.recommender_service.MarkRecommendationClaimedRequest.StateMetadataEntry]): - State properties to include with this state. Overwrites any - existing ``state_metadata``. - etag (str): - Fingerprint of the Recommendation. Provides - optimistic locking. - """ - - class StateMetadataEntry(proto.Message): - r""" - - Attributes: - key (str): - - value (str): - - """ - key = proto.Field(proto.STRING, number=1) - value = proto.Field(proto.STRING, number=2) - - name = proto.Field(proto.STRING, number=1) - state_metadata = proto.RepeatedField( - proto.MESSAGE, number=2, message=StateMetadataEntry - ) - etag = proto.Field(proto.STRING, number=3) - - -class MarkRecommendationSucceededRequest(proto.Message): - r"""Request for the ``MarkRecommendationSucceeded`` Method. - - Attributes: - name (str): - Name of the recommendation. - state_metadata (Sequence[~.recommender_service.MarkRecommendationSucceededRequest.StateMetadataEntry]): - State properties to include with this state. Overwrites any - existing ``state_metadata``. - etag (str): - Fingerprint of the Recommendation. Provides - optimistic locking. - """ - - class StateMetadataEntry(proto.Message): - r""" - - Attributes: - key (str): - - value (str): - - """ - key = proto.Field(proto.STRING, number=1) - value = proto.Field(proto.STRING, number=2) - - name = proto.Field(proto.STRING, number=1) - state_metadata = proto.RepeatedField( - proto.MESSAGE, number=2, message=StateMetadataEntry - ) - etag = proto.Field(proto.STRING, number=3) - - -class MarkRecommendationFailedRequest(proto.Message): - r"""Request for the ``MarkRecommendationFailed`` Method. - - Attributes: - name (str): - Name of the recommendation. - state_metadata (Sequence[~.recommender_service.MarkRecommendationFailedRequest.StateMetadataEntry]): - State properties to include with this state. Overwrites any - existing ``state_metadata``. - etag (str): - Fingerprint of the Recommendation. Provides - optimistic locking. - """ - - class StateMetadataEntry(proto.Message): - r""" - - Attributes: - key (str): - - value (str): - - """ - key = proto.Field(proto.STRING, number=1) - value = proto.Field(proto.STRING, number=2) - - name = proto.Field(proto.STRING, number=1) - state_metadata = proto.RepeatedField( - proto.MESSAGE, number=2, message=StateMetadataEntry - ) - etag = proto.Field(proto.STRING, number=3) - - -__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/recommender/nox.py b/recommender/nox.py new file mode 100644 index 000000000000..9cace48f3bbc --- /dev/null +++ b/recommender/nox.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from __future__ import absolute_import +import os + +import nox + + +@nox.session +def default(session): + return unit(session, 'default') + + +@nox.session +@nox.parametrize('py', ['2.7', '3.5', '3.6', '3.7']) +def unit(session, py): + """Run the unit test suite.""" + + # Run unit tests against all supported versions of Python. + if py != 'default': + session.interpreter = 'python{}'.format(py) + + # Set the virtualenv directory name. + session.virtualenv_dirname = 'unit-' + py + + # Install all test dependencies, then install this package in-place. + session.install('pytest', 'mock') + session.install('-e', '.') + + # Run py.test against the unit tests. + session.run('py.test', '--quiet', os.path.join('tests', 'unit')) + + +@nox.session +def lint_setup_py(session): + """Verify that setup.py is valid (including RST check).""" + session.interpreter = 'python3.6' + session.install('docutils', 'pygments') + session.run( + 'python', 'setup.py', 'check', '--restructuredtext', '--strict') \ No newline at end of file diff --git a/recommender/noxfile.py b/recommender/noxfile.py index 1f6797a2207f..a2eefbb6765f 100644 --- a/recommender/noxfile.py +++ b/recommender/noxfile.py @@ -86,13 +86,13 @@ def default(session): ) -@nox.session(python=["3.5", "3.6", "3.7"]) +@nox.session(python=["2.7", "3.5", "3.6", "3.7"]) def unit(session): """Run the unit test suite.""" default(session) -@nox.session(python=["3.7"]) +@nox.session(python=["2.7", "3.7"]) def system(session): """Run the system test suite.""" system_test_path = os.path.join("tests", "system.py") diff --git a/recommender/setup.py b/recommender/setup.py index dd367cb7b763..60a4ca14ebe8 100644 --- a/recommender/setup.py +++ b/recommender/setup.py @@ -1,29 +1,77 @@ # -*- coding: utf-8 -*- -import setuptools # type: ignore +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import io +import os + +import setuptools + + +name = "google-cloud-recommender" +description = "Recommender API API client library" +version = "0.1.0" +release_status = "Development Status :: 3 - Alpha" +dependencies = [ + "google-api-core[grpc] >= 1.14.0, < 2.0.0dev", + 'enum34; python_version < "3.4"', +] + + +package_root = os.path.abspath(os.path.dirname(__file__)) + +readme_filename = os.path.join(package_root, "README.rst") +with io.open(readme_filename, encoding="utf-8") as readme_file: + readme = readme_file.read() + +packages = [ + package for package in setuptools.find_packages() if package.startswith("google") +] + +namespaces = ["google"] +if "google.cloud" in packages: + namespaces.append("google.cloud") setuptools.setup( - name="google-cloud-recommender", - version="0.0.1", - packages=setuptools.PEP420PackageFinder.find(), - namespace_packages=("google", "google.cloud"), - platforms="Posix; MacOS X; Windows", - include_package_data=True, - install_requires=( - "google-api-core >= 1.8.0, < 2.0.0dev", - "googleapis-common-protos >= 1.5.8", - "grpcio >= 1.10.0", - "proto-plus >= 0.4.0", - ), + name=name, + version=version, + description=description, + long_description=readme, + author="Google LLC", + author_email="googleapis-packages@google.com", + license="Apache 2.0", + url="https://github.com/googleapis/google-cloud-python", classifiers=[ - "Development Status :: 3 - Alpha", + release_status, "Intended Audience :: Developers", - "Operating System :: OS Independent", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", + "Operating System :: OS Independent", "Topic :: Internet", - "Topic :: Software Development :: Libraries :: Python Modules", ], + platforms="Posix; MacOS X; Windows", + packages=packages, + namespace_packages=namespaces, + install_requires=dependencies, + include_package_data=True, zip_safe=False, ) diff --git a/recommender/synth.metadata b/recommender/synth.metadata index f63a3117c94b..bb5220e6cffa 100644 --- a/recommender/synth.metadata +++ b/recommender/synth.metadata @@ -1,12 +1,19 @@ { - "updateTime": "2019-09-20T18:07:54.249961Z", + "updateTime": "2019-09-20T22:41:44.198208Z", "sources": [ + { + "generator": { + "name": "artman", + "version": "0.36.3", + "dockerImage": "googleapis/artman@sha256:66ca01f27ef7dc50fbfb7743b67028115a6a8acf43b2d82f9fc826de008adac4" + } + }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "2e02174cad304dac67a40e1f63885964c4db91b2", - "internalRef": "270249401" + "sha": "999d0930cea7a7cb3147a7c5432e1f011060d549", + "internalRef": "270363949" } }, { @@ -24,7 +31,8 @@ "apiName": "recommender", "apiVersion": "v1beta1", "language": "python", - "generator": "gapic-generator-python" + "generator": "gapic", + "config": "google/cloud/recommender/artman_recommender_v1beta1.yaml" } } ] diff --git a/recommender/synth.py b/recommender/synth.py index 9795678d6628..0e795e068a29 100644 --- a/recommender/synth.py +++ b/recommender/synth.py @@ -18,7 +18,7 @@ import synthtool as s from synthtool import gcp -gapic = gcp.GAPICMicrogenerator() +gapic = gcp.GAPICGenerator() versions = ["v1beta1"] common = gcp.CommonTemplates() @@ -28,61 +28,14 @@ # ---------------------------------------------------------------------------- for version in versions: library = gapic.py_library( - "recommender", version, proto_path=f"google/cloud/recommender/{version}", + "recommender", version ) - s.move(library, excludes="noxfile.py") - -# https://github.com/googleapis/gapic-generator-python/pull/175 -s.replace("google/cloud/**/*.py", -""", -(\s+)\) ->""", -""" -\g<1>) ->""") - -# Fix lint errors about unused variables in tests -# TODO: Add GitHub issue here -s.replace("tests/**/test_recommender.py", -"""(\s+)call\.return_value = recommender_service\.ListRecommendationsResponse\(\) -(\s+)response = client\.list_recommendations\(request\)""", -"""\g<1>call.return_value = recommender_service.ListRecommendationsResponse() -\g<2>client.list_recommendations(request)""") - -s.replace("tests/**/test_recommender.py", -"""(\s+)call\.return_value = recommendation\.Recommendation\(\) -(\s+)response = client\.get_recommendation\(request\)""", -"""\g<1>call.return_value = recommendation.Recommendation() -\g<2>client.get_recomemndation(request)""") - - -s.replace("tests/**/test_recommender.py", -"""(\s+)with pytest\.raises\(ValueError\): -(\s+)client = Recommender\( -(\s+)credentials=credentials\.AnonymousCredentials\(\), -(\s+)transport=transport, -(\s+)\) -""", -"""\g<1>with pytest.raises(ValueError): -\g<2>Recommender( -\g<3>credentials=credentials.AnonymousCredentials(), -\g<4>transport=transport -\g<5>) -""") - -s.replace("tests/**/test_recommender.py", -"""(\s+)client = Recommender\(\) -(\s+)adc\.assert_called_once_with\(""", -"""\g<1>Recommender() -\g<2>adc.assert_called_once_with(""") - -# Fix formatting in docstring -s.replace("google/cloud/**/recommendation.py", -"""(Example:\s+\{.+?\})""", -"""``\g<1>``""", flags=re.DOTALL) + s.move(library, excludes=['nox.py']) # ---------------------------------------------------------------------------- # Add templated files # ---------------------------------------------------------------------------- templated_files = common.py_library(unit_cov_level=97, cov_level=100) -s.move(templated_files, excludes=["noxfile.py"]) +s.move(templated_files) s.shell.run(["nox", "-s", "blacken"], hide_output=False) \ No newline at end of file diff --git a/recommender/tests/system.py b/recommender/tests/system.py index 5a5196b52f1b..fce8e7347d2f 100644 --- a/recommender/tests/system.py +++ b/recommender/tests/system.py @@ -24,6 +24,8 @@ class TestRecommender(unittest.TestCase): def test_list_recommendations(self): client = Recommender() PROJECT_ID = os.environ.get("PROJECT_ID") - parent = f"projects/{PROJECT_ID}/locations/global" + RECOMMENDER_ID = "google.compute.instanceGroupManager.MachineTypeRecommender" + parent = f"projects/{PROJECT_ID}/locations/global/recommender/{RECOMMENDER_ID}" + print(parent) request = ListRecommendationsRequest(parent=parent) - client.list_recommendations(request=request) \ No newline at end of file + client.list_recommendations(request=request) diff --git a/recommender/tests/unit/gapic/v1beta1/test_recommender_client_v1beta1.py b/recommender/tests/unit/gapic/v1beta1/test_recommender_client_v1beta1.py new file mode 100644 index 000000000000..dafe315484bf --- /dev/null +++ b/recommender/tests/unit/gapic/v1beta1/test_recommender_client_v1beta1.py @@ -0,0 +1,324 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Unit tests.""" + +import mock +import pytest + +from google.cloud import recommender_v1beta1 +from google.cloud.recommender_v1beta1.proto import recommendation_pb2 +from google.cloud.recommender_v1beta1.proto import recommender_service_pb2 + + +class MultiCallableStub(object): + """Stub for the grpc.UnaryUnaryMultiCallable interface.""" + + def __init__(self, method, channel_stub): + self.method = method + self.channel_stub = channel_stub + + def __call__(self, request, timeout=None, metadata=None, credentials=None): + self.channel_stub.requests.append((self.method, request)) + + response = None + if self.channel_stub.responses: + response = self.channel_stub.responses.pop() + + if isinstance(response, Exception): + raise response + + if response: + return response + + +class ChannelStub(object): + """Stub for the grpc.Channel interface.""" + + def __init__(self, responses=[]): + self.responses = responses + self.requests = [] + + def unary_unary(self, method, request_serializer=None, response_deserializer=None): + return MultiCallableStub(method, self) + + +class CustomException(Exception): + pass + + +class TestRecommenderClient(object): + def test_list_recommendations(self): + # Setup Expected Response + next_page_token = "" + recommendations_element = {} + recommendations = [recommendations_element] + expected_response = { + "next_page_token": next_page_token, + "recommendations": recommendations, + } + expected_response = recommender_service_pb2.ListRecommendationsResponse( + **expected_response + ) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup Request + parent = client.recommender_path("[PROJECT]", "[LOCATION]", "[RECOMMENDER]") + + paged_list_response = client.list_recommendations(parent) + resources = list(paged_list_response) + assert len(resources) == 1 + + assert expected_response.recommendations[0] == resources[0] + + assert len(channel.requests) == 1 + expected_request = recommender_service_pb2.ListRecommendationsRequest( + parent=parent + ) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_list_recommendations_exception(self): + channel = ChannelStub(responses=[CustomException()]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup request + parent = client.recommender_path("[PROJECT]", "[LOCATION]", "[RECOMMENDER]") + + paged_list_response = client.list_recommendations(parent) + with pytest.raises(CustomException): + list(paged_list_response) + + def test_get_recommendation(self): + # Setup Expected Response + name_2 = "name2-1052831874" + description = "description-1724546052" + recommender_subtype = "recommenderSubtype-1488504412" + etag = "etag3123477" + expected_response = { + "name": name_2, + "description": description, + "recommender_subtype": recommender_subtype, + "etag": etag, + } + expected_response = recommendation_pb2.Recommendation(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup Request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + + response = client.get_recommendation(name) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = recommender_service_pb2.GetRecommendationRequest(name=name) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_get_recommendation_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + + with pytest.raises(CustomException): + client.get_recommendation(name) + + def test_mark_recommendation_claimed(self): + # Setup Expected Response + name_2 = "name2-1052831874" + description = "description-1724546052" + recommender_subtype = "recommenderSubtype-1488504412" + etag_2 = "etag2-1293302904" + expected_response = { + "name": name_2, + "description": description, + "recommender_subtype": recommender_subtype, + "etag": etag_2, + } + expected_response = recommendation_pb2.Recommendation(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup Request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + etag = "etag3123477" + + response = client.mark_recommendation_claimed(name, etag) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = recommender_service_pb2.MarkRecommendationClaimedRequest( + name=name, etag=etag + ) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_mark_recommendation_claimed_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + etag = "etag3123477" + + with pytest.raises(CustomException): + client.mark_recommendation_claimed(name, etag) + + def test_mark_recommendation_succeeded(self): + # Setup Expected Response + name_2 = "name2-1052831874" + description = "description-1724546052" + recommender_subtype = "recommenderSubtype-1488504412" + etag_2 = "etag2-1293302904" + expected_response = { + "name": name_2, + "description": description, + "recommender_subtype": recommender_subtype, + "etag": etag_2, + } + expected_response = recommendation_pb2.Recommendation(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup Request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + etag = "etag3123477" + + response = client.mark_recommendation_succeeded(name, etag) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = recommender_service_pb2.MarkRecommendationSucceededRequest( + name=name, etag=etag + ) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_mark_recommendation_succeeded_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + etag = "etag3123477" + + with pytest.raises(CustomException): + client.mark_recommendation_succeeded(name, etag) + + def test_mark_recommendation_failed(self): + # Setup Expected Response + name_2 = "name2-1052831874" + description = "description-1724546052" + recommender_subtype = "recommenderSubtype-1488504412" + etag_2 = "etag2-1293302904" + expected_response = { + "name": name_2, + "description": description, + "recommender_subtype": recommender_subtype, + "etag": etag_2, + } + expected_response = recommendation_pb2.Recommendation(**expected_response) + + # Mock the API response + channel = ChannelStub(responses=[expected_response]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup Request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + etag = "etag3123477" + + response = client.mark_recommendation_failed(name, etag) + assert expected_response == response + + assert len(channel.requests) == 1 + expected_request = recommender_service_pb2.MarkRecommendationFailedRequest( + name=name, etag=etag + ) + actual_request = channel.requests[0][1] + assert expected_request == actual_request + + def test_mark_recommendation_failed_exception(self): + # Mock the API response + channel = ChannelStub(responses=[CustomException()]) + patch = mock.patch("google.api_core.grpc_helpers.create_channel") + with patch as create_channel: + create_channel.return_value = channel + client = recommender_v1beta1.RecommenderClient() + + # Setup request + name = client.recommendation_path( + "[PROJECT]", "[LOCATION]", "[RECOMMENDER]", "[RECOMMENDATION]" + ) + etag = "etag3123477" + + with pytest.raises(CustomException): + client.mark_recommendation_failed(name, etag) diff --git a/recommender/tests/unit/recommender_v1beta1/test_recommender.py b/recommender/tests/unit/recommender_v1beta1/test_recommender.py deleted file mode 100644 index a3da3f99be43..000000000000 --- a/recommender/tests/unit/recommender_v1beta1/test_recommender.py +++ /dev/null @@ -1,345 +0,0 @@ -# -*- coding: utf-8 -*- -from unittest import mock - -import grpc - -import pytest - -from google import auth -from google.auth import credentials -from google.cloud.recommender_v1beta1.services.recommender import Recommender -from google.cloud.recommender_v1beta1.services.recommender import pagers -from google.cloud.recommender_v1beta1.services.recommender import transports -from google.cloud.recommender_v1beta1.types import recommendation -from google.cloud.recommender_v1beta1.types import recommender_service - - -def test_list_recommendations(transport: str = "grpc"): - client = Recommender( - credentials=credentials.AnonymousCredentials(), transport=transport - ) - - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = recommender_service.ListRecommendationsRequest() - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.list_recommendations), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = recommender_service.ListRecommendationsResponse( - next_page_token="next_page_token_value" - ) - response = client.list_recommendations(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the response is the type that we expect. - assert isinstance(response, pagers.ListRecommendationsPager) - assert response.next_page_token == "next_page_token_value" - - -def test_list_recommendations_field_headers(): - client = Recommender(credentials=credentials.AnonymousCredentials()) - - # Any value that is part of the HTTP/1.1 URI should be sent as - # a field header. Set these to a non-empty value. - request = recommender_service.ListRecommendationsRequest(parent="parent/value") - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.list_recommendations), "__call__" - ) as call: - call.return_value = recommender_service.ListRecommendationsResponse() - client.list_recommendations(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the field header was sent. - _, _, kw = call.mock_calls[0] - assert ("x-goog-request-params", "parent=parent/value") in kw["metadata"] - - -def test_list_recommendations_pager(): - client = Recommender(credentials=credentials.AnonymousCredentials) - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.list_recommendations), "__call__" - ) as call: - # Set the response to a series of pages. - call.side_effect = ( - recommender_service.ListRecommendationsResponse( - recommendations=[ - recommendation.Recommendation(), - recommendation.Recommendation(), - recommendation.Recommendation(), - ], - next_page_token="abc", - ), - recommender_service.ListRecommendationsResponse( - recommendations=[], next_page_token="def" - ), - recommender_service.ListRecommendationsResponse( - recommendations=[recommendation.Recommendation()], next_page_token="ghi" - ), - recommender_service.ListRecommendationsResponse( - recommendations=[ - recommendation.Recommendation(), - recommendation.Recommendation(), - ] - ), - RuntimeError, - ) - results = [i for i in client.list_recommendations(request={})] - assert len(results) == 6 - assert all([isinstance(i, recommendation.Recommendation) for i in results]) - - -def test_get_recommendation(transport: str = "grpc"): - client = Recommender( - credentials=credentials.AnonymousCredentials(), transport=transport - ) - - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = recommender_service.GetRecommendationRequest() - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.get_recommendation), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = recommendation.Recommendation( - name="name_value", - description="description_value", - recommender_subtype="recommender_subtype_value", - etag="etag_value", - ) - response = client.get_recommendation(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the response is the type that we expect. - assert isinstance(response, recommendation.Recommendation) - assert response.name == "name_value" - assert response.description == "description_value" - assert response.recommender_subtype == "recommender_subtype_value" - assert response.etag == "etag_value" - - -def test_get_recommendation_field_headers(): - client = Recommender(credentials=credentials.AnonymousCredentials()) - - # Any value that is part of the HTTP/1.1 URI should be sent as - # a field header. Set these to a non-empty value. - request = recommender_service.GetRecommendationRequest(name="name/value") - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.get_recommendation), "__call__" - ) as call: - call.return_value = recommendation.Recommendation() - client.get_recomemndation(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the field header was sent. - _, _, kw = call.mock_calls[0] - assert ("x-goog-request-params", "name=name/value") in kw["metadata"] - - -def test_mark_recommendation_claimed(transport: str = "grpc"): - client = Recommender( - credentials=credentials.AnonymousCredentials(), transport=transport - ) - - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = recommender_service.MarkRecommendationClaimedRequest() - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.mark_recommendation_claimed), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = recommendation.Recommendation( - name="name_value", - description="description_value", - recommender_subtype="recommender_subtype_value", - etag="etag_value", - ) - response = client.mark_recommendation_claimed(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the response is the type that we expect. - assert isinstance(response, recommendation.Recommendation) - assert response.name == "name_value" - assert response.description == "description_value" - assert response.recommender_subtype == "recommender_subtype_value" - assert response.etag == "etag_value" - - -def test_mark_recommendation_succeeded(transport: str = "grpc"): - client = Recommender( - credentials=credentials.AnonymousCredentials(), transport=transport - ) - - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = recommender_service.MarkRecommendationSucceededRequest() - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.mark_recommendation_succeeded), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = recommendation.Recommendation( - name="name_value", - description="description_value", - recommender_subtype="recommender_subtype_value", - etag="etag_value", - ) - response = client.mark_recommendation_succeeded(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the response is the type that we expect. - assert isinstance(response, recommendation.Recommendation) - assert response.name == "name_value" - assert response.description == "description_value" - assert response.recommender_subtype == "recommender_subtype_value" - assert response.etag == "etag_value" - - -def test_mark_recommendation_failed(transport: str = "grpc"): - client = Recommender( - credentials=credentials.AnonymousCredentials(), transport=transport - ) - - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = recommender_service.MarkRecommendationFailedRequest() - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client._transport.mark_recommendation_failed), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = recommendation.Recommendation( - name="name_value", - description="description_value", - recommender_subtype="recommender_subtype_value", - etag="etag_value", - ) - response = client.mark_recommendation_failed(request) - - # Establish that the underlying gRPC stub method was called. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - assert args[0] == request - - # Establish that the response is the type that we expect. - assert isinstance(response, recommendation.Recommendation) - assert response.name == "name_value" - assert response.description == "description_value" - assert response.recommender_subtype == "recommender_subtype_value" - assert response.etag == "etag_value" - - -def test_credentials_transport_error(): - # It is an error to provide credentials and a transport instance. - transport = transports.RecommenderGrpcTransport( - credentials=credentials.AnonymousCredentials() - ) - with pytest.raises(ValueError): - Recommender(credentials=credentials.AnonymousCredentials(), transport=transport) - - -def test_transport_instance(): - # A client may be instantiated with a custom transport instance. - transport = transports.RecommenderGrpcTransport( - credentials=credentials.AnonymousCredentials() - ) - client = Recommender(transport=transport) - assert client._transport is transport - - -def test_transport_grpc_default(): - # A client should use the gRPC transport by default. - client = Recommender(credentials=credentials.AnonymousCredentials()) - assert isinstance(client._transport, transports.RecommenderGrpcTransport) - - -def test_recommender_base_transport(): - # Instantiate the base transport. - transport = transports.RecommenderTransport( - credentials=credentials.AnonymousCredentials() - ) - - # Every method on the transport should just blindly - # raise NotImplementedError. - methods = ( - "list_recommendations", - "get_recommendation", - "mark_recommendation_claimed", - "mark_recommendation_succeeded", - "mark_recommendation_failed", - ) - for method in methods: - with pytest.raises(NotImplementedError): - getattr(transport, method)(request=object()) - - -def test_recommender_auth_adc(): - # If no credentials are provided, we should use ADC credentials. - with mock.patch.object(auth, "default") as adc: - adc.return_value = (credentials.AnonymousCredentials(), None) - Recommender() - adc.assert_called_once_with( - scopes=("https://www.googleapis.com/auth/cloud-platform",) - ) - - -def test_recommender_host_no_port(): - client = Recommender( - credentials=credentials.AnonymousCredentials(), - host="recommender.googleapis.com", - transport="grpc", - ) - assert client._transport._host == "recommender.googleapis.com:443" - - -def test_recommender_host_with_port(): - client = Recommender( - credentials=credentials.AnonymousCredentials(), - host="recommender.googleapis.com:8000", - transport="grpc", - ) - assert client._transport._host == "recommender.googleapis.com:8000" - - -def test_recommender_grpc_transport_channel(): - channel = grpc.insecure_channel("http://localhost/") - transport = transports.RecommenderGrpcTransport(channel=channel) - assert transport.grpc_channel is channel From 6b1849bb7a8241fb2407f3a12c5148141b8b0821 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 15:52:59 -0700 Subject: [PATCH 05/14] Remove old nox.py --- recommender/nox.py | 55 ---------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 recommender/nox.py diff --git a/recommender/nox.py b/recommender/nox.py deleted file mode 100644 index 9cace48f3bbc..000000000000 --- a/recommender/nox.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2019 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -from __future__ import absolute_import -import os - -import nox - - -@nox.session -def default(session): - return unit(session, 'default') - - -@nox.session -@nox.parametrize('py', ['2.7', '3.5', '3.6', '3.7']) -def unit(session, py): - """Run the unit test suite.""" - - # Run unit tests against all supported versions of Python. - if py != 'default': - session.interpreter = 'python{}'.format(py) - - # Set the virtualenv directory name. - session.virtualenv_dirname = 'unit-' + py - - # Install all test dependencies, then install this package in-place. - session.install('pytest', 'mock') - session.install('-e', '.') - - # Run py.test against the unit tests. - session.run('py.test', '--quiet', os.path.join('tests', 'unit')) - - -@nox.session -def lint_setup_py(session): - """Verify that setup.py is valid (including RST check).""" - session.interpreter = 'python3.6' - session.install('docutils', 'pygments') - session.run( - 'python', 'setup.py', 'check', '--restructuredtext', '--strict') \ No newline at end of file From 8203a9f96e7b23aaf15cf922cbe3a4a2bf9a3815 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 15:53:06 -0700 Subject: [PATCH 06/14] Rewrite system test. --- recommender/tests/system.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/recommender/tests/system.py b/recommender/tests/system.py index fce8e7347d2f..1017170312ca 100644 --- a/recommender/tests/system.py +++ b/recommender/tests/system.py @@ -16,16 +16,14 @@ import os import unittest -from google.cloud.recommender_v1beta1.services.recommender import Recommender -from google.cloud.recommender_v1beta1 import ListRecommendationsRequest +from google.cloud import recommender_v1beta1 class TestRecommender(unittest.TestCase): def test_list_recommendations(self): - client = Recommender() - PROJECT_ID = os.environ.get("PROJECT_ID") - RECOMMENDER_ID = "google.compute.instanceGroupManager.MachineTypeRecommender" - parent = f"projects/{PROJECT_ID}/locations/global/recommender/{RECOMMENDER_ID}" - print(parent) - request = ListRecommendationsRequest(parent=parent) - client.list_recommendations(request=request) + client = recommender_v1beta1.RecommenderClient() + project_id = os.environ.get('PROJECT_ID') + location = 'global' + recommender = 'google.iam.policy.RoleRecommender' + parent = client.recommender_path(project_id, location, recommender) + client.list_recommendations(parent) \ No newline at end of file From d8ba93c45af60a1eea89bb53e1fc78cd2ecdae4c Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 15:59:23 -0700 Subject: [PATCH 07/14] Add repo metadata. --- recommender/.repo-metadata.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 recommender/.repo-metadata.json diff --git a/recommender/.repo-metadata.json b/recommender/.repo-metadata.json new file mode 100644 index 000000000000..b3598c302da7 --- /dev/null +++ b/recommender/.repo-metadata.json @@ -0,0 +1,13 @@ +{ + "name": "recommender", + "name_pretty": "Cloud Recommender API", + "product_documentation": "https://cloud.google.com/recommender", + "client_documentation": "https://googleapis.dev/python/recommender/latest", + "issue_tracker": "", + "release_level": "alpha", + "language": "python", + "repo": "googleapis/google-cloud-python", + "distribution_name": "google-cloud-recommender", + "api_id": "recommender.googleapis.com", + "requires_billing": true +} \ No newline at end of file From 153c9c5998f5028093777660fa7505a33386f2e3 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 16:02:26 -0700 Subject: [PATCH 08/14] Blacken. --- recommender/tests/system.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/recommender/tests/system.py b/recommender/tests/system.py index 1017170312ca..5b8c20e57661 100644 --- a/recommender/tests/system.py +++ b/recommender/tests/system.py @@ -22,8 +22,8 @@ class TestRecommender(unittest.TestCase): def test_list_recommendations(self): client = recommender_v1beta1.RecommenderClient() - project_id = os.environ.get('PROJECT_ID') - location = 'global' - recommender = 'google.iam.policy.RoleRecommender' + project_id = os.environ.get("PROJECT_ID") + location = "global" + recommender = "google.iam.policy.RoleRecommender" parent = client.recommender_path(project_id, location, recommender) - client.list_recommendations(parent) \ No newline at end of file + client.list_recommendations(parent) From 29a6841934982cfab4872eb24e29974d7f816a2f Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 20 Sep 2019 16:05:25 -0700 Subject: [PATCH 09/14] Compatible with Python >=3.5 --- recommender/README.rst | 5 +++++ recommender/setup.py | 15 +++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/recommender/README.rst b/recommender/README.rst index 306ef7feaca4..1a15fb6fb850 100644 --- a/recommender/README.rst +++ b/recommender/README.rst @@ -40,6 +40,11 @@ dependencies. .. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ +Supported Python Versions +^^^^^^^^^^^^^^^^^^^^^^^^^ +Python >= 3.5 + + Mac/Linux ^^^^^^^^^ diff --git a/recommender/setup.py b/recommender/setup.py index 60a4ca14ebe8..ddb514c1b4e1 100644 --- a/recommender/setup.py +++ b/recommender/setup.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright 2019 Google LLC +# Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,17 +19,14 @@ import setuptools - name = "google-cloud-recommender" -description = "Recommender API API client library" +description = "Cloud Recommender API client library" version = "0.1.0" release_status = "Development Status :: 3 - Alpha" dependencies = [ "google-api-core[grpc] >= 1.14.0, < 2.0.0dev", - 'enum34; python_version < "3.4"', ] - package_root = os.path.abspath(os.path.dirname(__file__)) readme_filename = os.path.join(package_root, "README.rst") @@ -44,7 +41,6 @@ if "google.cloud" in packages: namespaces.append("google.cloud") - setuptools.setup( name=name, version=version, @@ -53,18 +49,16 @@ author="Google LLC", author_email="googleapis-packages@google.com", license="Apache 2.0", - url="https://github.com/googleapis/google-cloud-python", + url="https://github.com/GoogleCloudPlatform/google-cloud-python", classifiers=[ release_status, "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Operating System :: OS Independent", "Topic :: Internet", ], @@ -72,6 +66,7 @@ packages=packages, namespace_packages=namespaces, install_requires=dependencies, + python_requires=">=3.5", include_package_data=True, zip_safe=False, ) From b12b80a2fc2b0e7acb1388bcb60f40b2d0bd53d6 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Tue, 24 Sep 2019 22:47:36 -0400 Subject: [PATCH 10/14] chore: drop 2.7 tests, fix links --- recommender/README.rst | 4 ++-- recommender/noxfile.py | 4 ++-- recommender/setup.py | 4 +--- recommender/synth.py | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/recommender/README.rst b/recommender/README.rst index 1a15fb6fb850..bfa5e7bfd58d 100644 --- a/recommender/README.rst +++ b/recommender/README.rst @@ -9,7 +9,7 @@ Python Client for Recommender API (`Alpha`_) .. _Alpha: https://github.com/googleapis/google-cloud-python/blob/master/README.rst .. _Recommender API: https://cloud.google.com/recommender .. _Client Library Documentation: https://googleapis.github.io/google-cloud-python/latest/recommender/usage.html -.. _Product Documentation: https://cloud.google.com/recommender +.. _Product Documentation: https://cloud.google.com/recommender/docs Quick Start ----------- @@ -24,7 +24,7 @@ In order to use this library, you first need to go through the following steps: .. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project .. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project .. _Enable the Recommender API.: https://cloud.google.com/recommender -.. _Setup Authentication.: https://googleapis.github.io/google-cloud-python/latest/core/auth.html +.. _Setup Authentication.: https://googleapis.dev/python/google-api-core/latest/auth.html Installation ~~~~~~~~~~~~ diff --git a/recommender/noxfile.py b/recommender/noxfile.py index a2eefbb6765f..1f6797a2207f 100644 --- a/recommender/noxfile.py +++ b/recommender/noxfile.py @@ -86,13 +86,13 @@ def default(session): ) -@nox.session(python=["2.7", "3.5", "3.6", "3.7"]) +@nox.session(python=["3.5", "3.6", "3.7"]) def unit(session): """Run the unit test suite.""" default(session) -@nox.session(python=["2.7", "3.7"]) +@nox.session(python=["3.7"]) def system(session): """Run the system test suite.""" system_test_path = os.path.join("tests", "system.py") diff --git a/recommender/setup.py b/recommender/setup.py index ddb514c1b4e1..31a46fd840eb 100644 --- a/recommender/setup.py +++ b/recommender/setup.py @@ -23,9 +23,7 @@ description = "Cloud Recommender API client library" version = "0.1.0" release_status = "Development Status :: 3 - Alpha" -dependencies = [ - "google-api-core[grpc] >= 1.14.0, < 2.0.0dev", -] +dependencies = ["google-api-core[grpc] >= 1.14.0, < 2.0.0dev"] package_root = os.path.abspath(os.path.dirname(__file__)) diff --git a/recommender/synth.py b/recommender/synth.py index 0e795e068a29..c314c12f4503 100644 --- a/recommender/synth.py +++ b/recommender/synth.py @@ -36,6 +36,6 @@ # Add templated files # ---------------------------------------------------------------------------- templated_files = common.py_library(unit_cov_level=97, cov_level=100) -s.move(templated_files) +s.move(templated_files, excludes=['noxfile.py']) s.shell.run(["nox", "-s", "blacken"], hide_output=False) \ No newline at end of file From 317aaa060652ce954f490cc97c7e6a4e7e114321 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Thu, 26 Sep 2019 14:47:00 -0400 Subject: [PATCH 11/14] docs: update docs/conf.py --- recommender/docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recommender/docs/conf.py b/recommender/docs/conf.py index 4f8382a64bd6..ba1f5d62862c 100644 --- a/recommender/docs/conf.py +++ b/recommender/docs/conf.py @@ -344,7 +344,7 @@ "google-gax": ("https://gax-python.readthedocs.io/en/latest/", None), "google.api_core": ("https://googleapis.dev/python/google-api-core/latest", None), "grpc": ("https://grpc.io/grpc/python/", None), - "requests": ("https://2.python-requests.org/en/master/", None), + "requests": ("https://requests.kennethreitz.org/en/stable/", None), "fastavro": ("https://fastavro.readthedocs.io/en/stable/", None), "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), } From dc2bbf8a44001044e37d8766dee07ff2ab397c25 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 27 Sep 2019 09:41:22 -0700 Subject: [PATCH 12/14] chore: add ignores to synth, fix docs --- recommender/docs/README.rst | 1 + recommender/docs/index.rst | 76 +----- .../proto/recommendation.proto | 234 ++++++++++++++++++ .../proto/recommender_service.proto | 190 ++++++++++++++ recommender/synth.metadata | 10 +- recommender/synth.py | 5 +- 6 files changed, 434 insertions(+), 82 deletions(-) create mode 120000 recommender/docs/README.rst create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/recommendation.proto create mode 100644 recommender/google/cloud/recommender_v1beta1/proto/recommender_service.proto diff --git a/recommender/docs/README.rst b/recommender/docs/README.rst new file mode 120000 index 000000000000..89a0106941ff --- /dev/null +++ b/recommender/docs/README.rst @@ -0,0 +1 @@ +../README.rst \ No newline at end of file diff --git a/recommender/docs/index.rst b/recommender/docs/index.rst index 1405c9ab2208..37c319bfaffe 100644 --- a/recommender/docs/index.rst +++ b/recommender/docs/index.rst @@ -1,78 +1,4 @@ -Python Client for Recommender API (`Alpha`_) -============================================ - -`Recommender API`_: - -- `Client Library Documentation`_ -- `Product Documentation`_ - -.. _Alpha: https://github.com/googleapis/google-cloud-python/blob/master/README.rst -.. _Recommender API: https://cloud.google.com/recommender -.. _Client Library Documentation: https://googleapis.github.io/google-cloud-python/latest/recommender/usage.html -.. _Product Documentation: https://cloud.google.com/recommender - -Quick Start ------------ - -In order to use this library, you first need to go through the following steps: - -1. `Select or create a Cloud Platform project.`_ -2. `Enable billing for your project.`_ -3. `Enable the Recommender API.`_ -4. `Setup Authentication.`_ - -.. _Select or create a Cloud Platform project.: https://console.cloud.google.com/project -.. _Enable billing for your project.: https://cloud.google.com/billing/docs/how-to/modify-project#enable_billing_for_a_project -.. _Enable the Recommender API.: https://cloud.google.com/recommender -.. _Setup Authentication.: https://googleapis.github.io/google-cloud-python/latest/core/auth.html - -Installation -~~~~~~~~~~~~ - -Install this library in a `virtualenv`_ using pip. `virtualenv`_ is a tool to -create isolated Python environments. The basic problem it addresses is one of -dependencies and versions, and indirectly permissions. - -With `virtualenv`_, it's possible to install this library without needing system -install permissions, and without clashing with the installed system -dependencies. - -.. _`virtualenv`: https://virtualenv.pypa.io/en/latest/ - - -Mac/Linux -^^^^^^^^^ - -.. code-block:: console - - pip install virtualenv - virtualenv - source /bin/activate - /bin/pip install google-cloud-recommender - - -Windows -^^^^^^^ - -.. code-block:: console - - pip install virtualenv - virtualenv - \Scripts\activate - \Scripts\pip.exe install google-cloud-recommender - -Next Steps -~~~~~~~~~~ - -- Read the `Client Library Documentation`_ for Recommender API - API to see other available methods on the client. -- Read the `Recommender API Product documentation`_ to learn - more about the product and see How-to Guides. -- View this `repository’s main README`_ to see the full list of Cloud - APIs that we cover. - -.. _Recommender API Product documentation: https://cloud.google.com/recommender -.. _repository’s main README: https://github.com/googleapis/google-cloud-python/blob/master/README.rst +.. include:: README.rst Api Reference ------------- diff --git a/recommender/google/cloud/recommender_v1beta1/proto/recommendation.proto b/recommender/google/cloud/recommender_v1beta1/proto/recommendation.proto new file mode 100644 index 000000000000..8980de0c4274 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/proto/recommendation.proto @@ -0,0 +1,234 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.cloud.recommender.v1beta1; + +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +import "google/type/money.proto"; + +option csharp_namespace = "Google.Cloud.Recommender.V1Beta1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/recommender/v1beta1;recommender"; +option java_multiple_files = true; +option java_package = "com.google.cloud.recommender.v1beta1"; +option objc_class_prefix = "CREC"; + +// A recommendation along with a suggested action. E.g., a rightsizing +// recommendation for an underutilized VM, IAM role recommendations, etc +message Recommendation { + // Name of recommendation. + // + // A project recommendation is represented as + // projects/[PROJECT_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER_ID]/recommendations/[RECOMMENDATION_ID] + string name = 1; + + // Free-form human readable summary in English. The maximum length is 500 + // characters. + string description = 2; + + // Contains an identifier for a subtype of recommendations produced for the + // same recommender. Subtype is a function of content and impact, meaning a + // new subtype will be added when either content or primary impact category + // changes. + // + // Examples: + // For recommender = "google.iam.policy.RoleRecommender", + // recommender_subtype can be one of "REMOVE_ROLE"/"REPLACE_ROLE" + string recommender_subtype = 12; + + // Last time this recommendation was refreshed by the system that created it + // in the first place. + google.protobuf.Timestamp last_refresh_time = 4; + + // The primary impact that this recommendation can have while trying to + // optimize for one category. + Impact primary_impact = 5; + + // Optional set of additional impact that this recommendation may have when + // trying to optimize for the primary category. These may be positive + // or negative. + repeated Impact additional_impact = 6; + + // Content of the recommendation describing recommended changes to resources. + RecommendationContent content = 7; + + // Information for state. Contains state and metadata. + RecommendationStateInfo state_info = 10; + + // Fingerprint of the Recommendation. Provides optimistic locking when + // updating states. + string etag = 11; +} + +// Contains what resources are changing and how they are changing. +message RecommendationContent { + // Operations to one or more Google Cloud resources grouped in such a way + // that, all operations within one group are expected to be performed + // atomically and in an order. + repeated OperationGroup operation_groups = 2; +} + +// Group of operations that need to be performed atomically. +message OperationGroup { + // List of operations across one or more resources that belong to this group. + // Loosely based on RFC6902 and should be performed in the order they appear. + repeated Operation operations = 1; +} + +// Contains an operation for a resource inspired by the JSON-PATCH format with +// support for: +// * Custom filters for describing partial array patch. +// * Extended path values for describing nested arrays. +// * Custom fields for describing the resource for which the operation is being +// described. +// * Allows extension to custom operations not natively supported by RFC6902. +// See https://tools.ietf.org/html/rfc6902 for details on the original RFC. +message Operation { + // Type of this operation. Contains one of 'and', 'remove', 'replace', 'move', + // 'copy', 'test' and custom operations. This field is case-insensitive and + // always populated. + string action = 1; + + // Type of GCP resource being modified/tested. This field is always populated. + // Example: cloudresourcemanager.googleapis.com/Project, + // compute.googleapis.com/Instance + string resource_type = 2; + + // Contains the fully qualified resource name. This field is always populated. + // ex: //cloudresourcemanager.googleapis.com/projects/foo. + string resource = 3; + + // Path to the target field being operated on. If the operation is at the + // resource level, then path should be "/". This field is always populated. + string path = 4; + + // Can be set with action 'copy' to copy resource configuration across + // different resources of the same type. Example: A resource clone can be + // done via action = 'copy', path = "/", from = "/", + // source_resource = and resource_name = . + // This field is empty for all other values of `action`. + string source_resource = 5; + + // Can be set with action 'copy' or 'move' to indicate the source field within + // resource or source_resource, ignored if provided for other operation types. + string source_path = 6; + + // Value for the `path` field. Set if action is 'add'/'replace'/'test'. + google.protobuf.Value value = 7; + + // Set of filters to apply if `path` refers to array elements or nested array + // elements in order to narrow down to a single unique element that is being + // tested/modified. + // Note that this is intended to be an exact match per filter. + // Example: { + // "/versions/*/name" : "it-123" + // "/versions/*/targetSize/percent": 20 + // } + // Example: { + // "/bindings/*/role": "roles/admin" + // "/bindings/*/condition" : null + // } + // Example: { + // "/bindings/*/role": "roles/admin" + // "/bindings/*/members/*" : ["x@google.com", "y@google.com"] + // } + map path_filters = 8; +} + +// Contains metadata about how much money a recommendation can save or incur. +message CostProjection { + // An approximate projection on amount saved or amount incurred. Negative cost + // units indicate cost savings and positive cost units indicate increase. + // See google.type.Money documentation for positive/negative units. + google.type.Money cost = 1; + + // Duration for which this cost applies. + google.protobuf.Duration duration = 2; +} + +// Contains the impact a recommendation can have for a given category. +message Impact { + // The category of the impact. + enum Category { + // Default unspecified category. Don't use directly. + CATEGORY_UNSPECIFIED = 0; + + // Indicates a potential increase or decrease in cost. + COST = 1; + + // Indicates a potential increase or decrease in security. + SECURITY = 2; + + // Indicates a potential increase or decrease in performance. + PERFORMANCE = 3; + } + + // Category that is being targeted. + Category category = 1; + + // Contains projections (if any) for this category. + oneof projection { + // Use with CategoryType.COST + CostProjection cost_projection = 100; + } +} + +// Information for state. Contains state and metadata. +message RecommendationStateInfo { + // Represents Recommendation State + enum State { + // Default state. Don't use directly. + STATE_UNSPECIFIED = 0; + + // Recommendation is active and can be applied. Recommendations content can + // be updated by Google. + // + // ACTIVE recommendations can be marked as CLAIMED, SUCCEEDED, or FAILED. + ACTIVE = 1; + + // Recommendation is in claimed state. Recommendations content is + // immutable and cannot be updated by Google. + // + // CLAIMED recommendations can be marked as CLAIMED, SUCCEEDED, or FAILED. + CLAIMED = 6; + + // Recommendation is in succeeded state. Recommendations content is + // immutable and cannot be updated by Google. + // + // SUCCEEDED recommendations can be marked as SUCCEEDED, or FAILED. + SUCCEEDED = 3; + + // Recommendation is in failed state. Recommendations content is immutable + // and cannot be updated by Google. + // + // FAILED recommendations can be marked as SUCCEEDED, or FAILED. + FAILED = 4; + + // Recommendation is in dismissed state. Recommendation content can be + // updated by Google. + // + // DISMISSED recommendations can be marked as ACTIVE. + DISMISSED = 5; + } + + // The state of the recommendation, Eg ACTIVE, SUCCEEDED, FAILED. + State state = 1; + + // A map of metadata for the state, provided by user or automations systems. + map state_metadata = 2; +} diff --git a/recommender/google/cloud/recommender_v1beta1/proto/recommender_service.proto b/recommender/google/cloud/recommender_v1beta1/proto/recommender_service.proto new file mode 100644 index 000000000000..49a076ae74f6 --- /dev/null +++ b/recommender/google/cloud/recommender_v1beta1/proto/recommender_service.proto @@ -0,0 +1,190 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.cloud.recommender.v1beta1; + +import "google/api/annotations.proto"; +import "google/cloud/recommender/v1beta1/recommendation.proto"; +import "google/longrunning/operations.proto"; +import "google/api/client.proto"; + +option csharp_namespace = "Google.Cloud.Recommmender.V1Beta1"; +option go_package = "google.golang.org/genproto/googleapis/cloud/recommender/v1beta1;recommender"; +option java_multiple_files = true; +option java_outer_classname = "RecommenderProto"; +option java_package = "com.google.cloud.recommender.v1beta1"; +option objc_class_prefix = "CREC"; + +// Provides recommendations for cloud customers for various categories like +// performance optimization, cost savings, reliability, feature discovery, etc. +// These recommendations are generated automatically based on analysis of user +// resources, configuration and monitoring metrics. +service Recommender { + option (google.api.default_host) = "recommender.googleapis.com"; + option (google.api.oauth_scopes) = "https://www.googleapis.com/auth/cloud-platform"; + + // Lists recommendations for a Cloud project. Requires the recommender.*.list + // IAM permission for the specified recommender. + rpc ListRecommendations(ListRecommendationsRequest) returns (ListRecommendationsResponse) { + option (google.api.http) = { + get: "/v1beta1/{parent=projects/*/locations/*/recommenders/*}/recommendations" + }; + } + + // Gets the requested recommendation. Requires the recommender.*.get + // IAM permission for the specified recommender. + rpc GetRecommendation(GetRecommendationRequest) returns (Recommendation) { + option (google.api.http) = { + get: "/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}" + }; + } + + // Mark the Recommendation State as Claimed. Users can use this method to + // indicate to the Recommender API that they are starting to apply the + // recommendation themselves. This stops the recommendation content from being + // updated. + // + // MarkRecommendationClaimed can be applied to recommendations in CLAIMED, + // SUCCEEDED, FAILED, or ACTIVE state. + // + // Requires the recommender.*.update IAM permission for the specified + // recommender. + rpc MarkRecommendationClaimed(MarkRecommendationClaimedRequest) returns (Recommendation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markClaimed" + body: "*" + }; + } + + // Mark the Recommendation State as Succeeded. Users can use this method to + // indicate to the Recommender API that they have applied the recommendation + // themselves, and the operation was successful. This stops the recommendation + // content from being updated. + // + // MarkRecommendationSucceeded can be applied to recommendations in ACTIVE, + // CLAIMED, SUCCEEDED, or FAILED state. + // + // Requires the recommender.*.update IAM permission for the specified + // recommender. + rpc MarkRecommendationSucceeded(MarkRecommendationSucceededRequest) returns (Recommendation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markSucceeded" + body: "*" + }; + } + + // Mark the Recommendation State as Failed. Users can use this method to + // indicate to the Recommender API that they have applied the recommendation + // themselves, and the operation failed. This stops the recommendation content + // from being updated. + // + // MarkRecommendationFailed can be applied to recommendations in ACTIVE, + // CLAIMED, SUCCEEDED, or FAILED state. + // + // Requires the recommender.*.update IAM permission for the specified + // recommender. + rpc MarkRecommendationFailed(MarkRecommendationFailedRequest) returns (Recommendation) { + option (google.api.http) = { + post: "/v1beta1/{name=projects/*/locations/*/recommenders/*/recommendations/*}:markFailed" + body: "*" + }; + } +} + +// Request for the `ListRecommendations` method. +message ListRecommendationsRequest { + // Required. The container resource on which to execute the request. + // Acceptable formats: + // + // 1. + // "projects/[PROJECT_NUMBER]/locations/[LOCATION]/recommenders/[RECOMMENDER_ID]", + // + // LOCATION here refers to GCP Locations: + // https://cloud.google.com/about/locations/ + string parent = 1; + + // Optional. The maximum number of results to return from this request. + // Non-positive values are ignored. If not specified, the server will + // determine the number of results to return. + int32 page_size = 2; + + // Optional. If present, retrieves the next batch of results from the + // preceding call to this method. `page_token` must be the value of + // `next_page_token` from the previous response. The values of other method + // parameters must be identical to those in the previous call. + string page_token = 3; + + // Filter expression to restrict the recommendations returned. Supported + // filter fields: state_info.state + // Eg: `state_info.state:"DISMISSED" or state_info.state:"FAILED" + string filter = 5; +} + +// Response to the `ListRecommendations` method. +message ListRecommendationsResponse { + // The set of recommendations for the `parent` resource. + repeated Recommendation recommendations = 1; + + // A token that can be used to request the next page of results. This field is + // empty if there are no additional results. + string next_page_token = 2; +} + +// Request to the `GetRecommendation` method. +message GetRecommendationRequest { + // Name of the recommendation. + string name = 1; +} + +// Request for the `MarkRecommendationClaimed` Method. +message MarkRecommendationClaimedRequest { + // Name of the recommendation. + string name = 1; + + // State properties to include with this state. Overwrites any existing + // `state_metadata`. + map state_metadata = 2; + + // Fingerprint of the Recommendation. Provides optimistic locking. + string etag = 3; +} + +// Request for the `MarkRecommendationSucceeded` Method. +message MarkRecommendationSucceededRequest { + // Name of the recommendation. + string name = 1; + + // State properties to include with this state. Overwrites any existing + // `state_metadata`. + map state_metadata = 2; + + // Fingerprint of the Recommendation. Provides optimistic locking. + string etag = 3; +} + +// Request for the `MarkRecommendationFailed` Method. +message MarkRecommendationFailedRequest { + // Name of the recommendation. + string name = 1; + + // State properties to include with this state. Overwrites any existing + // `state_metadata`. + map state_metadata = 2; + + // Fingerprint of the Recommendation. Provides optimistic locking. + string etag = 3; +} diff --git a/recommender/synth.metadata b/recommender/synth.metadata index bb5220e6cffa..2de372bf0e0a 100644 --- a/recommender/synth.metadata +++ b/recommender/synth.metadata @@ -1,19 +1,19 @@ { - "updateTime": "2019-09-20T22:41:44.198208Z", + "updateTime": "2019-09-27T16:39:53.634316Z", "sources": [ { "generator": { "name": "artman", - "version": "0.36.3", - "dockerImage": "googleapis/artman@sha256:66ca01f27ef7dc50fbfb7743b67028115a6a8acf43b2d82f9fc826de008adac4" + "version": "0.37.1", + "dockerImage": "googleapis/artman@sha256:6068f67900a3f0bdece596b97bda8fc70406ca0e137a941f4c81d3217c994a80" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "999d0930cea7a7cb3147a7c5432e1f011060d549", - "internalRef": "270363949" + "sha": "cd112d8d255e0099df053643d4bd12c228ef7b1b", + "internalRef": "271468707" } }, { diff --git a/recommender/synth.py b/recommender/synth.py index c314c12f4503..93d445f42f11 100644 --- a/recommender/synth.py +++ b/recommender/synth.py @@ -28,9 +28,10 @@ # ---------------------------------------------------------------------------- for version in versions: library = gapic.py_library( - "recommender", version + "recommender", version, + include_protos=True ) - s.move(library, excludes=['nox.py']) + s.move(library, excludes=['nox.py', 'docs/index.rst', 'README.rst', 'setup.py']) # ---------------------------------------------------------------------------- # Add templated files From be03ab2f30f074485f29caf317212f147eab5073 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 27 Sep 2019 09:43:03 -0700 Subject: [PATCH 13/14] test(recommender): get response iterator in system test --- recommender/tests/system.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recommender/tests/system.py b/recommender/tests/system.py index 5b8c20e57661..79bd86c84df5 100644 --- a/recommender/tests/system.py +++ b/recommender/tests/system.py @@ -26,4 +26,4 @@ def test_list_recommendations(self): location = "global" recommender = "google.iam.policy.RoleRecommender" parent = client.recommender_path(project_id, location, recommender) - client.list_recommendations(parent) + list(client.list_recommendations(parent)) From d13c7755205511c8dd5e4c6000c61a7269538744 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 27 Sep 2019 10:48:08 -0700 Subject: [PATCH 14/14] test(recommender): remove system test --- recommender/tests/system.py | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 recommender/tests/system.py diff --git a/recommender/tests/system.py b/recommender/tests/system.py deleted file mode 100644 index 79bd86c84df5..000000000000 --- a/recommender/tests/system.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2019 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import unittest - -from google.cloud import recommender_v1beta1 - - -class TestRecommender(unittest.TestCase): - def test_list_recommendations(self): - client = recommender_v1beta1.RecommenderClient() - project_id = os.environ.get("PROJECT_ID") - location = "global" - recommender = "google.iam.policy.RoleRecommender" - parent = client.recommender_path(project_id, location, recommender) - list(client.list_recommendations(parent))