Merge branch 'master' of github.com:pulumi/pulumi
This commit is contained in:
commit
bf886cd53a
|
@ -19,6 +19,7 @@ include:
|
|||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
* Contribute in a positive and constructive way
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
|
@ -30,6 +31,12 @@ Examples of unacceptable behavior by participants include:
|
|||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Community Guidelines
|
||||
* Be clear and stay on topic. Communicating with strangers on the Internet can make it hard to convey or read tone, and sarcasm is frequently misunderstood. Try to use clear language, and think about how the other person will receive it.
|
||||
* Don’t cross-post the same thing in multiple GitHub Discussion topics or multiple Slack channels. This can make it difficult for people answering your questions and creates "scrollback spam".
|
||||
* Public discussion is preferred to private. Avoid using Slack DMs for questions, and instead share them in public Slack channels or GitHub Discussion threads. This allows a larger audience to both share their knowledge as well as learn from your question or issue. If you're having a problem, chances are someone else is having a similar problem. Learning in public is a community contribution.
|
||||
* Minimize notifications to other community members. Avoid tagging other community members in Slack messages or Discussion threads, unless you are replying to something specific. Community members are here to help each other, but are not "on call" for support, and we expect everyone to try to minimize "notification fatigue". If your issue is time-sensitive or critical, use methods like support@pulumi.com instead.
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@ var sdkTests = []sdkTest{
|
|||
Directory: "simple-resource-schema-custom-pypackage-name",
|
||||
Description: "Simple schema with local resource properties and custom Python package name",
|
||||
},
|
||||
// TODO[pulumi/pulumi#7072]: Enable test after codegen support for all languages lands.
|
||||
// {
|
||||
// Directory: "simple-methods-schema",
|
||||
// Description: "Simple schema with methods",
|
||||
// },
|
||||
}
|
||||
|
||||
// TestSDKCodegen runs the complete set of SDK code generation tests against a particular language's code generator.
|
||||
|
|
0
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/README.md
vendored
Normal file
0
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/README.md
vendored
Normal file
40
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/__init__.py
vendored
Normal file
40
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/__init__.py
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
from . import _utilities
|
||||
import typing
|
||||
# Export this package's modules as members:
|
||||
from .foo import *
|
||||
from .provider import *
|
||||
|
||||
# Make subpackages available:
|
||||
if typing.TYPE_CHECKING:
|
||||
import pulumi_example.nested as nested
|
||||
else:
|
||||
nested = _utilities.lazy_import('pulumi_example.nested')
|
||||
|
||||
_utilities.register(
|
||||
resource_modules="""
|
||||
[
|
||||
{
|
||||
"pkg": "example",
|
||||
"mod": "",
|
||||
"fqn": "pulumi_example",
|
||||
"classes": {
|
||||
"example::Foo": "Foo"
|
||||
}
|
||||
}
|
||||
]
|
||||
""",
|
||||
resource_packages="""
|
||||
[
|
||||
{
|
||||
"pkg": "example",
|
||||
"token": "pulumi:providers:example",
|
||||
"fqn": "pulumi_example",
|
||||
"class": "Provider"
|
||||
}
|
||||
]
|
||||
"""
|
||||
)
|
211
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/_utilities.py
vendored
Normal file
211
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/_utilities.py
vendored
Normal file
|
@ -0,0 +1,211 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import importlib.util
|
||||
import pkg_resources
|
||||
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
|
||||
from semver import VersionInfo as SemverVersion
|
||||
from parver import Version as PEP440Version
|
||||
|
||||
|
||||
def get_env(*args):
|
||||
for v in args:
|
||||
value = os.getenv(v)
|
||||
if value is not None:
|
||||
return value
|
||||
return None
|
||||
|
||||
|
||||
def get_env_bool(*args):
|
||||
str = get_env(*args)
|
||||
if str is not None:
|
||||
# NOTE: these values are taken from https://golang.org/src/strconv/atob.go?s=351:391#L1, which is what
|
||||
# Terraform uses internally when parsing boolean values.
|
||||
if str in ["1", "t", "T", "true", "TRUE", "True"]:
|
||||
return True
|
||||
if str in ["0", "f", "F", "false", "FALSE", "False"]:
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def get_env_int(*args):
|
||||
str = get_env(*args)
|
||||
if str is not None:
|
||||
try:
|
||||
return int(str)
|
||||
except:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def get_env_float(*args):
|
||||
str = get_env(*args)
|
||||
if str is not None:
|
||||
try:
|
||||
return float(str)
|
||||
except:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def _get_semver_version():
|
||||
# __name__ is set to the fully-qualified name of the current module, In our case, it will be
|
||||
# <some module>._utilities. <some module> is the module we want to query the version for.
|
||||
root_package, *rest = __name__.split('.')
|
||||
|
||||
# pkg_resources uses setuptools to inspect the set of installed packages. We use it here to ask
|
||||
# for the currently installed version of the root package (i.e. us) and get its version.
|
||||
|
||||
# Unfortunately, PEP440 and semver differ slightly in incompatible ways. The Pulumi engine expects
|
||||
# to receive a valid semver string when receiving requests from the language host, so it's our
|
||||
# responsibility as the library to convert our own PEP440 version into a valid semver string.
|
||||
|
||||
pep440_version_string = pkg_resources.require(root_package)[0].version
|
||||
pep440_version = PEP440Version.parse(pep440_version_string)
|
||||
(major, minor, patch) = pep440_version.release
|
||||
prerelease = None
|
||||
if pep440_version.pre_tag == 'a':
|
||||
prerelease = f"alpha.{pep440_version.pre}"
|
||||
elif pep440_version.pre_tag == 'b':
|
||||
prerelease = f"beta.{pep440_version.pre}"
|
||||
elif pep440_version.pre_tag == 'rc':
|
||||
prerelease = f"rc.{pep440_version.pre}"
|
||||
elif pep440_version.dev is not None:
|
||||
prerelease = f"dev.{pep440_version.dev}"
|
||||
|
||||
# The only significant difference between PEP440 and semver as it pertains to us is that PEP440 has explicit support
|
||||
# for dev builds, while semver encodes them as "prerelease" versions. In order to bridge between the two, we convert
|
||||
# our dev build version into a prerelease tag. This matches what all of our other packages do when constructing
|
||||
# their own semver string.
|
||||
return SemverVersion(major=major, minor=minor, patch=patch, prerelease=prerelease)
|
||||
|
||||
|
||||
# Determine the version once and cache the value, which measurably improves program performance.
|
||||
_version = _get_semver_version()
|
||||
_version_str = str(_version)
|
||||
|
||||
|
||||
def get_version():
|
||||
return _version_str
|
||||
|
||||
|
||||
def get_resource_args_opts(resource_args_type, resource_options_type, *args, **kwargs):
|
||||
"""
|
||||
Return the resource args and options given the *args and **kwargs of a resource's
|
||||
__init__ method.
|
||||
"""
|
||||
|
||||
resource_args, opts = None, None
|
||||
|
||||
# If the first item is the resource args type, save it and remove it from the args list.
|
||||
if args and isinstance(args[0], resource_args_type):
|
||||
resource_args, args = args[0], args[1:]
|
||||
|
||||
# Now look at the first item in the args list again.
|
||||
# If the first item is the resource options class, save it.
|
||||
if args and isinstance(args[0], resource_options_type):
|
||||
opts = args[0]
|
||||
|
||||
# If resource_args is None, see if "args" is in kwargs, and, if so, if it's typed as the
|
||||
# the resource args type.
|
||||
if resource_args is None:
|
||||
a = kwargs.get("args")
|
||||
if isinstance(a, resource_args_type):
|
||||
resource_args = a
|
||||
|
||||
# If opts is None, look it up in kwargs.
|
||||
if opts is None:
|
||||
opts = kwargs.get("opts")
|
||||
|
||||
return resource_args, opts
|
||||
|
||||
|
||||
# Temporary: just use pulumi._utils.lazy_import once everyone upgrades.
|
||||
def lazy_import(fullname):
|
||||
|
||||
import pulumi._utils as u
|
||||
f = getattr(u, 'lazy_import', None)
|
||||
if f is None:
|
||||
f = _lazy_import_temp
|
||||
|
||||
return f(fullname)
|
||||
|
||||
|
||||
# Copied from pulumi._utils.lazy_import, see comments there.
|
||||
def _lazy_import_temp(fullname):
|
||||
m = sys.modules.get(fullname, None)
|
||||
if m is not None:
|
||||
return m
|
||||
|
||||
spec = importlib.util.find_spec(fullname)
|
||||
|
||||
m = sys.modules.get(fullname, None)
|
||||
if m is not None:
|
||||
return m
|
||||
|
||||
loader = importlib.util.LazyLoader(spec.loader)
|
||||
spec.loader = loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
|
||||
m = sys.modules.get(fullname, None)
|
||||
if m is not None:
|
||||
return m
|
||||
|
||||
sys.modules[fullname] = module
|
||||
loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
class Package(pulumi.runtime.ResourcePackage):
|
||||
def __init__(self, pkg_info):
|
||||
super().__init__()
|
||||
self.pkg_info = pkg_info
|
||||
|
||||
def version(self):
|
||||
return _version
|
||||
|
||||
def construct_provider(self, name: str, typ: str, urn: str) -> pulumi.ProviderResource:
|
||||
if typ != self.pkg_info['token']:
|
||||
raise Exception(f"unknown provider type {typ}")
|
||||
Provider = getattr(lazy_import(self.pkg_info['fqn']), self.pkg_info['class'])
|
||||
return Provider(name, pulumi.ResourceOptions(urn=urn))
|
||||
|
||||
|
||||
class Module(pulumi.runtime.ResourceModule):
|
||||
def __init__(self, mod_info):
|
||||
super().__init__()
|
||||
self.mod_info = mod_info
|
||||
|
||||
def version(self):
|
||||
return _version
|
||||
|
||||
def construct(self, name: str, typ: str, urn: str) -> pulumi.Resource:
|
||||
class_name = self.mod_info['classes'].get(typ, None)
|
||||
|
||||
if class_name is None:
|
||||
raise Exception(f"unknown resource type {typ}")
|
||||
|
||||
TheClass = getattr(lazy_import(self.mod_info['fqn']), class_name)
|
||||
return TheClass(name, pulumi.ResourceOptions(urn=urn))
|
||||
|
||||
|
||||
def register(resource_modules, resource_packages):
|
||||
resource_modules = json.loads(resource_modules)
|
||||
resource_packages = json.loads(resource_packages)
|
||||
|
||||
for pkg_info in resource_packages:
|
||||
pulumi.runtime.register_resource_package(pkg_info['pkg'], Package(pkg_info))
|
||||
|
||||
for mod_info in resource_modules:
|
||||
pulumi.runtime.register_resource_module(
|
||||
mod_info['pkg'],
|
||||
mod_info['mod'],
|
||||
Module(mod_info))
|
127
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/foo.py
vendored
Normal file
127
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/foo.py
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import warnings
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
from typing import Any, Mapping, Optional, Sequence, Union, overload
|
||||
from . import _utilities
|
||||
from . import nested as _nested
|
||||
import pulumi_random
|
||||
|
||||
__all__ = ['FooArgs', 'Foo']
|
||||
|
||||
@pulumi.input_type
|
||||
class FooArgs:
|
||||
def __init__(__self__):
|
||||
"""
|
||||
The set of arguments for constructing a Foo resource.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Foo(pulumi.ComponentResource):
|
||||
@overload
|
||||
def __init__(__self__,
|
||||
resource_name: str,
|
||||
opts: Optional[pulumi.ResourceOptions] = None,
|
||||
__props__=None):
|
||||
"""
|
||||
Create a Foo resource with the given unique name, props, and options.
|
||||
:param str resource_name: The name of the resource.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def __init__(__self__,
|
||||
resource_name: str,
|
||||
args: Optional[FooArgs] = None,
|
||||
opts: Optional[pulumi.ResourceOptions] = None):
|
||||
"""
|
||||
Create a Foo resource with the given unique name, props, and options.
|
||||
:param str resource_name: The name of the resource.
|
||||
:param FooArgs args: The arguments to use to populate this resource's properties.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
...
|
||||
def __init__(__self__, resource_name: str, *args, **kwargs):
|
||||
resource_args, opts = _utilities.get_resource_args_opts(FooArgs, pulumi.ResourceOptions, *args, **kwargs)
|
||||
if resource_args is not None:
|
||||
__self__._internal_init(resource_name, opts, **resource_args.__dict__)
|
||||
else:
|
||||
__self__._internal_init(resource_name, *args, **kwargs)
|
||||
|
||||
def _internal_init(__self__,
|
||||
resource_name: str,
|
||||
opts: Optional[pulumi.ResourceOptions] = None,
|
||||
__props__=None):
|
||||
if opts is None:
|
||||
opts = pulumi.ResourceOptions()
|
||||
if not isinstance(opts, pulumi.ResourceOptions):
|
||||
raise TypeError('Expected resource options to be a ResourceOptions instance')
|
||||
if opts.version is None:
|
||||
opts.version = _utilities.get_version()
|
||||
if opts.id is not None:
|
||||
raise ValueError('ComponentResource classes do not support opts.id')
|
||||
else:
|
||||
if __props__ is not None:
|
||||
raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')
|
||||
__props__ = FooArgs.__new__(FooArgs)
|
||||
|
||||
super(Foo, __self__).__init__(
|
||||
'example::Foo',
|
||||
resource_name,
|
||||
__props__,
|
||||
opts,
|
||||
remote=True)
|
||||
|
||||
@pulumi.output_type
|
||||
class BarResult:
|
||||
def __init__(__self__, some_value=None):
|
||||
if some_value and not isinstance(some_value, str):
|
||||
raise TypeError("Expected argument 'some_value' to be a str")
|
||||
pulumi.set(__self__, "some_value", some_value)
|
||||
|
||||
@property
|
||||
@pulumi.getter(name="someValue")
|
||||
def some_value(self) -> str:
|
||||
return pulumi.get(self, "some_value")
|
||||
|
||||
def bar(__self__, *,
|
||||
baz_required: pulumi.Input['_nested.BazArgs'],
|
||||
bool_value_required: pulumi.Input[bool],
|
||||
name_required: pulumi.Input['pulumi_random.RandomPet'],
|
||||
string_value_required: pulumi.Input[str],
|
||||
baz: Optional[pulumi.Input['_nested.BazArgs']] = None,
|
||||
baz_plain: Optional['_nested.BazArgs'] = None,
|
||||
bool_value: Optional[pulumi.Input[bool]] = None,
|
||||
bool_value_plain: Optional[bool] = None,
|
||||
name: Optional[pulumi.Input['pulumi_random.RandomPet']] = None,
|
||||
name_plain: Optional['pulumi_random.RandomPet'] = None,
|
||||
string_value: Optional[pulumi.Input[str]] = None,
|
||||
string_value_plain: Optional[str] = None) -> pulumi.Output['Foo.BarResult']:
|
||||
"""
|
||||
A description of bar.
|
||||
"""
|
||||
__args__ = dict()
|
||||
__args__['__self__'] = __self__
|
||||
__args__['bazRequired'] = baz_required
|
||||
__args__['boolValueRequired'] = bool_value_required
|
||||
__args__['nameRequired'] = name_required
|
||||
__args__['stringValueRequired'] = string_value_required
|
||||
__args__['baz'] = baz
|
||||
__args__['bazPlain'] = baz_plain
|
||||
__args__['boolValue'] = bool_value
|
||||
__args__['boolValuePlain'] = bool_value_plain
|
||||
__args__['name'] = name
|
||||
__args__['namePlain'] = name_plain
|
||||
__args__['stringValue'] = string_value
|
||||
__args__['stringValuePlain'] = string_value_plain
|
||||
return pulumi.runtime.call('example::Foo/bar', __args__, res=__self__, typ=Foo.BarResult)
|
||||
|
||||
def baz(__self__) -> None:
|
||||
__args__ = dict()
|
||||
__args__['__self__'] = __self__
|
||||
pulumi.runtime.call('example::Foo/baz', __args__, res=__self__)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
from .. import _utilities
|
||||
import typing
|
||||
from ._inputs import *
|
43
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/nested/_inputs.py
vendored
Normal file
43
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/nested/_inputs.py
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import warnings
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
from typing import Any, Mapping, Optional, Sequence, Union, overload
|
||||
from .. import _utilities
|
||||
|
||||
__all__ = [
|
||||
'Baz',
|
||||
]
|
||||
|
||||
@pulumi.input_type
|
||||
class Baz:
|
||||
def __init__(__self__, *,
|
||||
hello: Optional[str] = None,
|
||||
world: Optional[str] = None):
|
||||
if hello is not None:
|
||||
pulumi.set(__self__, "hello", hello)
|
||||
if world is not None:
|
||||
pulumi.set(__self__, "world", world)
|
||||
|
||||
@property
|
||||
@pulumi.getter
|
||||
def hello(self) -> Optional[str]:
|
||||
return pulumi.get(self, "hello")
|
||||
|
||||
@hello.setter
|
||||
def hello(self, value: Optional[str]):
|
||||
pulumi.set(self, "hello", value)
|
||||
|
||||
@property
|
||||
@pulumi.getter
|
||||
def world(self) -> Optional[str]:
|
||||
return pulumi.get(self, "world")
|
||||
|
||||
@world.setter
|
||||
def world(self, value: Optional[str]):
|
||||
pulumi.set(self, "world", value)
|
||||
|
||||
|
73
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/provider.py
vendored
Normal file
73
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/provider.py
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import warnings
|
||||
import pulumi
|
||||
import pulumi.runtime
|
||||
from typing import Any, Mapping, Optional, Sequence, Union, overload
|
||||
from . import _utilities
|
||||
|
||||
__all__ = ['ProviderArgs', 'Provider']
|
||||
|
||||
@pulumi.input_type
|
||||
class ProviderArgs:
|
||||
def __init__(__self__):
|
||||
"""
|
||||
The set of arguments for constructing a Provider resource.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Provider(pulumi.ProviderResource):
|
||||
@overload
|
||||
def __init__(__self__,
|
||||
resource_name: str,
|
||||
opts: Optional[pulumi.ResourceOptions] = None,
|
||||
__props__=None):
|
||||
"""
|
||||
Create a Example resource with the given unique name, props, and options.
|
||||
:param str resource_name: The name of the resource.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
...
|
||||
@overload
|
||||
def __init__(__self__,
|
||||
resource_name: str,
|
||||
args: Optional[ProviderArgs] = None,
|
||||
opts: Optional[pulumi.ResourceOptions] = None):
|
||||
"""
|
||||
Create a Example resource with the given unique name, props, and options.
|
||||
:param str resource_name: The name of the resource.
|
||||
:param ProviderArgs args: The arguments to use to populate this resource's properties.
|
||||
:param pulumi.ResourceOptions opts: Options for the resource.
|
||||
"""
|
||||
...
|
||||
def __init__(__self__, resource_name: str, *args, **kwargs):
|
||||
resource_args, opts = _utilities.get_resource_args_opts(ProviderArgs, pulumi.ResourceOptions, *args, **kwargs)
|
||||
if resource_args is not None:
|
||||
__self__._internal_init(resource_name, opts, **resource_args.__dict__)
|
||||
else:
|
||||
__self__._internal_init(resource_name, *args, **kwargs)
|
||||
|
||||
def _internal_init(__self__,
|
||||
resource_name: str,
|
||||
opts: Optional[pulumi.ResourceOptions] = None,
|
||||
__props__=None):
|
||||
if opts is None:
|
||||
opts = pulumi.ResourceOptions()
|
||||
if not isinstance(opts, pulumi.ResourceOptions):
|
||||
raise TypeError('Expected resource options to be a ResourceOptions instance')
|
||||
if opts.version is None:
|
||||
opts.version = _utilities.get_version()
|
||||
if opts.id is None:
|
||||
if __props__ is not None:
|
||||
raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource')
|
||||
__props__ = ProviderArgs.__new__(ProviderArgs)
|
||||
|
||||
super(Provider, __self__).__init__(
|
||||
'example',
|
||||
resource_name,
|
||||
__props__,
|
||||
opts)
|
||||
|
0
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/py.typed
vendored
Normal file
0
pkg/codegen/internal/test/testdata/simple-methods-schema/python/pulumi_example/py.typed
vendored
Normal file
55
pkg/codegen/internal/test/testdata/simple-methods-schema/python/setup.py
vendored
Normal file
55
pkg/codegen/internal/test/testdata/simple-methods-schema/python/setup.py
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
# coding=utf-8
|
||||
# *** WARNING: this file was generated by test. ***
|
||||
# *** Do not edit by hand unless you're certain you know what you are doing! ***
|
||||
|
||||
import errno
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools.command.install import install
|
||||
from subprocess import check_call
|
||||
|
||||
|
||||
class InstallPluginCommand(install):
|
||||
def run(self):
|
||||
install.run(self)
|
||||
try:
|
||||
check_call(['pulumi', 'plugin', 'install', 'resource', 'example', '${PLUGIN_VERSION}'])
|
||||
except OSError as error:
|
||||
if error.errno == errno.ENOENT:
|
||||
print("""
|
||||
There was an error installing the example resource provider plugin.
|
||||
It looks like `pulumi` is not installed on your system.
|
||||
Please visit https://pulumi.com/ to install the Pulumi CLI.
|
||||
You may try manually installing the plugin by running
|
||||
`pulumi plugin install resource example ${PLUGIN_VERSION}`
|
||||
""")
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def readme():
|
||||
try:
|
||||
with open('README.md', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
except FileNotFoundError:
|
||||
return "example Pulumi Package - Development Version"
|
||||
|
||||
|
||||
setup(name='pulumi_example',
|
||||
version='${VERSION}',
|
||||
long_description=readme(),
|
||||
long_description_content_type='text/markdown',
|
||||
cmdclass={
|
||||
'install': InstallPluginCommand,
|
||||
},
|
||||
packages=find_packages(),
|
||||
package_data={
|
||||
'pulumi_example': [
|
||||
'py.typed',
|
||||
]
|
||||
},
|
||||
install_requires=[
|
||||
'parver>=0.2.1',
|
||||
'pulumi',
|
||||
'semver>=2.8.1'
|
||||
],
|
||||
zip_safe=False)
|
115
pkg/codegen/internal/test/testdata/simple-methods-schema/schema.json
vendored
Normal file
115
pkg/codegen/internal/test/testdata/simple-methods-schema/schema.json
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
{
|
||||
"version": "0.0.1",
|
||||
"name": "example",
|
||||
"types": {
|
||||
"example:nested:Baz": {
|
||||
"properties": {
|
||||
"hello": {
|
||||
"type": "string"
|
||||
},
|
||||
"world": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"example::Foo": {
|
||||
"isComponent": true,
|
||||
"methods": {
|
||||
"bar": "example::Foo/bar",
|
||||
"baz": "example::Foo/baz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"functions": {
|
||||
"example::Foo/bar": {
|
||||
"description": "A description of bar.",
|
||||
"inputs": {
|
||||
"properties": {
|
||||
"__self__": {
|
||||
"$ref": "#/resources/example::Foo"
|
||||
},
|
||||
"boolValue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"boolValueRequired": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"boolValuePlain": {
|
||||
"type": "boolean",
|
||||
"plain": true
|
||||
},
|
||||
"stringValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"stringValueRequired": {
|
||||
"type": "string"
|
||||
},
|
||||
"stringValuePlain": {
|
||||
"type": "string",
|
||||
"plain": true
|
||||
},
|
||||
"name": {
|
||||
"$ref": "/random/v2.3.1/schema.json#/resources/random:index%2FrandomPet:RandomPet"
|
||||
},
|
||||
"nameRequired": {
|
||||
"$ref": "/random/v2.3.1/schema.json#/resources/random:index%2FrandomPet:RandomPet"
|
||||
},
|
||||
"namePlain": {
|
||||
"$ref": "/random/v2.3.1/schema.json#/resources/random:index%2FrandomPet:RandomPet",
|
||||
"plain": true
|
||||
},
|
||||
"baz": {
|
||||
"$ref": "#/types/example:nested:Baz"
|
||||
},
|
||||
"bazRequired": {
|
||||
"$ref": "#/types/example:nested:Baz"
|
||||
},
|
||||
"bazPlain": {
|
||||
"$ref": "#/types/example:nested:Baz",
|
||||
"plain": true
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"__self__",
|
||||
"boolValueRequired",
|
||||
"stringValueRequired",
|
||||
"nameRequired",
|
||||
"bazRequired"
|
||||
]
|
||||
},
|
||||
"outputs": {
|
||||
"properties": {
|
||||
"someValue": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"someValue"
|
||||
]
|
||||
}
|
||||
},
|
||||
"example::Foo/baz": {
|
||||
"inputs": {
|
||||
"properties": {
|
||||
"__self__": {
|
||||
"$ref": "#/resources/example::Foo"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"__self__"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"csharp": {},
|
||||
"go": {
|
||||
"importBasePath": "github.com/pulumi/pulumi/pkg/v3/codegen/internal/test/testdata/simple-methods-schema/go/example"
|
||||
},
|
||||
"nodejs": {},
|
||||
"python": {}
|
||||
}
|
||||
}
|
|
@ -877,7 +877,7 @@ func (mod *modContext) genAwaitableType(w io.Writer, obj *schema.ObjectType) str
|
|||
fmt.Fprintf(w, "\n")
|
||||
|
||||
// Write out Python property getters for each property.
|
||||
mod.genProperties(w, obj.Properties, false /*setters*/, func(prop *schema.Property) string {
|
||||
mod.genProperties(w, obj.Properties, false /*setters*/, "", func(prop *schema.Property) string {
|
||||
return mod.typeString(prop.Type, false /*input*/, false /*acceptMapping*/)
|
||||
})
|
||||
|
||||
|
@ -909,22 +909,35 @@ func (mod *modContext) genAwaitableType(w io.Writer, obj *schema.ObjectType) str
|
|||
return awaitableName
|
||||
}
|
||||
|
||||
func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
||||
w := &bytes.Buffer{}
|
||||
|
||||
imports := imports{}
|
||||
mod.collectImports(res.Properties, imports, false /*input*/)
|
||||
mod.collectImports(res.InputProperties, imports, true /*input*/)
|
||||
if res.StateInputs != nil {
|
||||
mod.collectImports(res.StateInputs.Properties, imports, true /*input*/)
|
||||
}
|
||||
|
||||
mod.genHeader(w, true /*needsSDK*/, imports)
|
||||
|
||||
func resourceName(res *schema.Resource) string {
|
||||
name := pyClassName(tokenToName(res.Token))
|
||||
if res.IsProvider {
|
||||
name = "Provider"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
||||
w := &bytes.Buffer{}
|
||||
|
||||
imports := imports{}
|
||||
mod.collectImportsForResource(res.Properties, imports, false /*input*/, res)
|
||||
mod.collectImportsForResource(res.InputProperties, imports, true /*input*/, res)
|
||||
if res.StateInputs != nil {
|
||||
mod.collectImportsForResource(res.StateInputs.Properties, imports, true /*input*/, res)
|
||||
}
|
||||
for _, method := range res.Methods {
|
||||
if method.Function.Inputs != nil {
|
||||
mod.collectImportsForResource(method.Function.Inputs.Properties, imports, true /*input*/, res)
|
||||
}
|
||||
if method.Function.Outputs != nil {
|
||||
mod.collectImportsForResource(method.Function.Outputs.Properties, imports, false /*input*/, res)
|
||||
}
|
||||
}
|
||||
|
||||
mod.genHeader(w, true /*needsSDK*/, imports)
|
||||
|
||||
name := resourceName(res)
|
||||
|
||||
resourceArgsName := fmt.Sprintf("%sArgs", name)
|
||||
// Some providers (e.g. Kubernetes) have types with the same name as resources (e.g. StorageClass in Kubernetes).
|
||||
|
@ -1226,15 +1239,18 @@ func (mod *modContext) genResource(res *schema.Resource) (string, error) {
|
|||
}
|
||||
|
||||
// Write out Python property getters for each of the resource's properties.
|
||||
mod.genProperties(w, res.Properties, false /*setters*/, func(prop *schema.Property) string {
|
||||
mod.genProperties(w, res.Properties, false /*setters*/, "", func(prop *schema.Property) string {
|
||||
ty := mod.typeString(prop.Type, false /*input*/, false /*acceptMapping*/)
|
||||
return fmt.Sprintf("pulumi.Output[%s]", ty)
|
||||
})
|
||||
|
||||
// Write out methods.
|
||||
mod.genMethods(w, res)
|
||||
|
||||
return w.String(), nil
|
||||
}
|
||||
|
||||
func (mod *modContext) genProperties(w io.Writer, properties []*schema.Property, setters bool,
|
||||
func (mod *modContext) genProperties(w io.Writer, properties []*schema.Property, setters bool, indent string,
|
||||
propType func(prop *schema.Property) string) {
|
||||
// Write out Python properties for each property. If there is a property named "property", it will
|
||||
// be emitted last to avoid conflicting with the built-in `@property` decorator function. We do
|
||||
|
@ -1242,22 +1258,22 @@ func (mod *modContext) genProperties(w io.Writer, properties []*schema.Property,
|
|||
// because that wouldn't address the problem if there was a property named "builtins".
|
||||
emitProp := func(pname string, prop *schema.Property) {
|
||||
ty := propType(prop)
|
||||
fmt.Fprintf(w, " @property\n")
|
||||
fmt.Fprintf(w, "%s @property\n", indent)
|
||||
if pname == prop.Name {
|
||||
fmt.Fprintf(w, " @pulumi.getter\n")
|
||||
fmt.Fprintf(w, "%s @pulumi.getter\n", indent)
|
||||
} else {
|
||||
fmt.Fprintf(w, " @pulumi.getter(name=%q)\n", prop.Name)
|
||||
fmt.Fprintf(w, "%s @pulumi.getter(name=%q)\n", indent, prop.Name)
|
||||
}
|
||||
fmt.Fprintf(w, " def %s(self) -> %s:\n", pname, ty)
|
||||
fmt.Fprintf(w, "%s def %s(self) -> %s:\n", indent, pname, ty)
|
||||
if prop.Comment != "" {
|
||||
printComment(w, prop.Comment, " ")
|
||||
printComment(w, prop.Comment, indent+" ")
|
||||
}
|
||||
fmt.Fprintf(w, " return pulumi.get(self, %q)\n\n", pname)
|
||||
fmt.Fprintf(w, "%s return pulumi.get(self, %q)\n\n", indent, pname)
|
||||
|
||||
if setters {
|
||||
fmt.Fprintf(w, " @%s.setter\n", pname)
|
||||
fmt.Fprintf(w, " def %s(self, value: %s):\n", pname, ty)
|
||||
fmt.Fprintf(w, " pulumi.set(self, %q, value)\n\n", pname)
|
||||
fmt.Fprintf(w, "%s @%s.setter\n", indent, pname)
|
||||
fmt.Fprintf(w, "%s def %s(self, value: %s):\n", indent, pname, ty)
|
||||
fmt.Fprintf(w, "%s pulumi.set(self, %q, value)\n\n", indent, pname)
|
||||
}
|
||||
}
|
||||
var propNamedProperty *schema.Property
|
||||
|
@ -1275,6 +1291,152 @@ func (mod *modContext) genProperties(w io.Writer, properties []*schema.Property,
|
|||
}
|
||||
}
|
||||
|
||||
func (mod *modContext) genMethods(w io.Writer, res *schema.Resource) {
|
||||
genReturnType := func(method *schema.Method) string {
|
||||
obj := method.Function.Outputs
|
||||
name := pyClassName(title(method.Name)) + "Result"
|
||||
|
||||
// Produce a class definition with optional """ comment.
|
||||
fmt.Fprintf(w, " @pulumi.output_type\n")
|
||||
fmt.Fprintf(w, " class %s:\n", name)
|
||||
printComment(w, obj.Comment, " ")
|
||||
|
||||
// Now generate an initializer with properties for all inputs.
|
||||
fmt.Fprintf(w, " def __init__(__self__")
|
||||
for _, prop := range obj.Properties {
|
||||
fmt.Fprintf(w, ", %s=None", PyName(prop.Name))
|
||||
}
|
||||
fmt.Fprintf(w, "):\n")
|
||||
for _, prop := range obj.Properties {
|
||||
// Check that required arguments are present. Also check that types are as expected.
|
||||
pname := PyName(prop.Name)
|
||||
ptype := mod.pyType(prop.Type)
|
||||
fmt.Fprintf(w, " if %s and not isinstance(%s, %s):\n", pname, pname, ptype)
|
||||
fmt.Fprintf(w, " raise TypeError(\"Expected argument '%s' to be a %s\")\n", pname, ptype)
|
||||
|
||||
if prop.DeprecationMessage != "" {
|
||||
escaped := strings.ReplaceAll(prop.DeprecationMessage, `"`, `\"`)
|
||||
fmt.Fprintf(w, " if %s is not None:\n", pname)
|
||||
fmt.Fprintf(w, " warnings.warn(\"\"\"%s\"\"\", DeprecationWarning)\n", escaped)
|
||||
fmt.Fprintf(w, " pulumi.log.warn(\"\"\"%s is deprecated: %s\"\"\")\n\n", pname, escaped)
|
||||
}
|
||||
|
||||
// Now perform the assignment.
|
||||
fmt.Fprintf(w, " pulumi.set(__self__, \"%[1]s\", %[1]s)\n", pname)
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
|
||||
// Write out Python property getters for each property.
|
||||
mod.genProperties(w, obj.Properties, false /*setters*/, " ", func(prop *schema.Property) string {
|
||||
return mod.typeString(prop.Type, false /*input*/, false /*acceptMapping*/)
|
||||
})
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
genMethod := func(method *schema.Method) {
|
||||
methodName := PyName(method.Name)
|
||||
fun := method.Function
|
||||
|
||||
// If there is a return type, emit it.
|
||||
var retTypeName, retTypeNameQualified, retTypeNameQualifiedOutput string
|
||||
if fun.Outputs != nil {
|
||||
retTypeName = genReturnType(method)
|
||||
retTypeNameQualified = fmt.Sprintf("%s.%s", resourceName(res), retTypeName)
|
||||
retTypeNameQualifiedOutput = fmt.Sprintf("pulumi.Output['%s']", retTypeNameQualified)
|
||||
}
|
||||
|
||||
var args []*schema.Property
|
||||
if fun.Inputs != nil {
|
||||
// Filter out the __self__ argument from the inputs.
|
||||
args = make([]*schema.Property, 0, len(fun.Inputs.InputShape.Properties)-1)
|
||||
for _, arg := range fun.Inputs.InputShape.Properties {
|
||||
if arg.Name == "__self__" {
|
||||
continue
|
||||
}
|
||||
args = append(args, arg)
|
||||
}
|
||||
// Sort required args first.
|
||||
sort.Slice(args, func(i, j int) bool {
|
||||
pi, pj := args[i], args[j]
|
||||
switch {
|
||||
case pi.IsRequired() != pj.IsRequired():
|
||||
return pi.IsRequired() && !pj.IsRequired()
|
||||
default:
|
||||
return pi.Name < pj.Name
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Write out the function signature.
|
||||
def := fmt.Sprintf(" def %s(", methodName)
|
||||
var indent string
|
||||
if len(args) > 0 {
|
||||
indent = strings.Repeat(" ", len(def))
|
||||
}
|
||||
fmt.Fprintf(w, "%s__self__", def)
|
||||
// Bare `*` argument to force callers to use named arguments.
|
||||
if len(args) > 0 {
|
||||
fmt.Fprintf(w, ", *")
|
||||
}
|
||||
for _, arg := range args {
|
||||
pname := PyName(arg.Name)
|
||||
ty := mod.typeString(arg.Type, true, false /*acceptMapping*/)
|
||||
var defaultValue string
|
||||
if !arg.IsRequired() {
|
||||
defaultValue = " = None"
|
||||
}
|
||||
fmt.Fprintf(w, ",\n%s%s: %s%s", indent, pname, ty, defaultValue)
|
||||
}
|
||||
if retTypeNameQualifiedOutput != "" {
|
||||
fmt.Fprintf(w, ") -> %s:\n", retTypeNameQualifiedOutput)
|
||||
} else {
|
||||
fmt.Fprintf(w, ") -> None:\n")
|
||||
}
|
||||
|
||||
// If this func has documentation, write it at the top of the docstring, otherwise use a generic comment.
|
||||
docs := &bytes.Buffer{}
|
||||
if fun.Comment != "" {
|
||||
fmt.Fprintln(docs, codegen.FilterExamples(fun.Comment, "python"))
|
||||
}
|
||||
if len(args) > 0 {
|
||||
fmt.Fprintln(docs, "")
|
||||
for _, arg := range args {
|
||||
mod.genPropDocstring(docs, PyName(arg.Name), arg, false /*acceptMapping*/)
|
||||
}
|
||||
}
|
||||
printComment(w, docs.String(), " ")
|
||||
|
||||
if fun.DeprecationMessage != "" {
|
||||
fmt.Fprintf(w, " pulumi.log.warn(\"\"\"%s is deprecated: %s\"\"\")\n", methodName,
|
||||
fun.DeprecationMessage)
|
||||
}
|
||||
|
||||
// Copy the function arguments into a dictionary.
|
||||
fmt.Fprintf(w, " __args__ = dict()\n")
|
||||
fmt.Fprintf(w, " __args__['__self__'] = __self__\n")
|
||||
for _, arg := range args {
|
||||
pname := PyName(arg.Name)
|
||||
fmt.Fprintf(w, " __args__['%s'] = %s\n", arg.Name, pname)
|
||||
}
|
||||
|
||||
// Now simply call the function with the arguments.
|
||||
var typ, ret string
|
||||
if retTypeNameQualified != "" {
|
||||
// Pass along the private output_type we generated, so any nested output classes are instantiated by
|
||||
// the call.
|
||||
typ = fmt.Sprintf(", typ=%s", retTypeNameQualified)
|
||||
ret = "return "
|
||||
}
|
||||
fmt.Fprintf(w, " %spulumi.runtime.call('%s', __args__, res=__self__%s)\n", ret, fun.Token, typ)
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
|
||||
for _, method := range res.Methods {
|
||||
genMethod(method)
|
||||
}
|
||||
}
|
||||
|
||||
func (mod *modContext) writeAlias(w io.Writer, alias *schema.Alias) {
|
||||
fmt.Fprint(w, "pulumi.Alias(")
|
||||
parts := []string{}
|
||||
|
@ -1500,6 +1662,11 @@ func visitObjectTypes(properties []*schema.Property, visitor func(objectOrResour
|
|||
}
|
||||
|
||||
func (mod *modContext) collectImports(properties []*schema.Property, imports imports, input bool) {
|
||||
mod.collectImportsForResource(properties, imports, input, nil)
|
||||
}
|
||||
|
||||
func (mod *modContext) collectImportsForResource(properties []*schema.Property, imports imports, input bool,
|
||||
res *schema.Resource) {
|
||||
codegen.VisitTypeClosure(properties, func(t schema.Type) {
|
||||
switch t := t.(type) {
|
||||
case *schema.ObjectType:
|
||||
|
@ -1507,7 +1674,10 @@ func (mod *modContext) collectImports(properties []*schema.Property, imports imp
|
|||
case *schema.EnumType:
|
||||
imports.addEnum(mod, t.Token)
|
||||
case *schema.ResourceType:
|
||||
imports.addResource(mod, t)
|
||||
// Don't import itself.
|
||||
if t.Resource != res {
|
||||
imports.addResource(mod, t)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -2164,7 +2334,7 @@ func (mod *modContext) genType(w io.Writer, name, comment string, properties []*
|
|||
fmt.Fprintf(w, "\n")
|
||||
|
||||
// Generate properties. Input types have getters and setters, output types only have getters.
|
||||
mod.genProperties(w, props, input /*setters*/, func(prop *schema.Property) string {
|
||||
mod.genProperties(w, props, input /*setters*/, "", func(prop *schema.Property) string {
|
||||
return mod.typeString(prop.Type, input, false /*acceptMapping*/)
|
||||
})
|
||||
|
||||
|
@ -2342,7 +2512,9 @@ func generateModuleContextMap(tool string, pkg *schema.Package, info PackageInfo
|
|||
// Find input and output types referenced by functions.
|
||||
for _, f := range pkg.Functions {
|
||||
mod := getModFromToken(f.Token, f.Package)
|
||||
mod.functions = append(mod.functions, f)
|
||||
if !f.IsMethod {
|
||||
mod.functions = append(mod.functions, f)
|
||||
}
|
||||
if f.Inputs != nil {
|
||||
visitObjectTypes(f.Inputs.Properties, func(t schema.Type) {
|
||||
switch T := t.(type) {
|
||||
|
|
|
@ -280,6 +280,7 @@ func newPlugin(ctx *Context, pwd, bin, prefix string, args, env []string, option
|
|||
// execPlugin starts the plugin executable.
|
||||
func execPlugin(bin string, pluginArgs []string, pwd string, env []string) (*plugin, error) {
|
||||
var args []string
|
||||
args = append(args, pluginArgs...)
|
||||
// Flow the logging information if set.
|
||||
if logging.LogFlow {
|
||||
if logging.LogToStderr {
|
||||
|
@ -293,7 +294,6 @@ func execPlugin(bin string, pluginArgs []string, pwd string, env []string) (*plu
|
|||
if cmdutil.TracingEndpoint != "" && !cmdutil.TracingToFile {
|
||||
args = append(args, "--tracing", cmdutil.TracingEndpoint)
|
||||
}
|
||||
args = append(args, pluginArgs...)
|
||||
|
||||
cmd := exec.Command(bin, args...)
|
||||
cmdutil.RegisterProcessGroup(cmd)
|
||||
|
|
|
@ -189,6 +189,9 @@ def main(provider: Provider, args: List[str]) -> None: # args not in use?
|
|||
|
||||
argp = argparse.ArgumentParser(description='Pulumi provider plugin (gRPC server)')
|
||||
argp.add_argument('engine', help='Pulumi engine address')
|
||||
argp.add_argument('--logflow', action='store_true', help='Currently ignored')
|
||||
argp.add_argument('--logtostderr', action='store_true', help='Currently ignored')
|
||||
|
||||
engine_address: str = argp.parse_args().engine
|
||||
|
||||
async def serve() -> None:
|
||||
|
|
|
@ -892,6 +892,8 @@ func optsForConstructNode(t *testing.T, expectedResourceCount int, env ...string
|
|||
},
|
||||
Quick: true,
|
||||
NoParallel: true,
|
||||
// verify that additional flags don't cause the component provider hang
|
||||
UpdateCommandlineFlags: []string{"--logflow", "--logtostderr"},
|
||||
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
||||
assert.NotNil(t, stackInfo.Deployment)
|
||||
if assert.Equal(t, expectedResourceCount, len(stackInfo.Deployment.Resources)) {
|
||||
|
|
Loading…
Reference in a new issue