Add Python Guestbook Component Example
MODIFY
aws-ts-stackreference/README.md
aws-ts-stackreference/README.md
@@ -18,7 +18,7 @@ stacks via [StackReference](https://www.pulumi.com/docs/intro/concepts/organizin
```bash
$ cd company
$ npm install
- ````
+ ```
1. Create a new stack:

MODIFY
kubernetes-py-guestbook/.gitignore
kubernetes-py-guestbook/.gitignore
@@ -308,6 +308,7 @@ paket-files/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
+venv
# Cake - Uncomment if you are using it
# tools/**

MODIFY
kubernetes-py-guestbook/README.md
kubernetes-py-guestbook/README.md
-[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new?template=https://github.com/pulumi/examples/tree/master/kubernetes-py-guestbook/simple)
+[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new?template=https://github.com/pulumi/examples/tree/master/kubernetes-ts-guestbook/components)
-# Simple Guestbook App
+# Simple and Component-based Kubernetes Guestbook Apps
A port of the standard [Kubernetes Guestbook](https://kubernetes.io/docs/tutorials/stateless-application/guestbook/)
to Pulumi. This example shows you how to build and deploy a simple, multi-tier web application using Kubernetes and
@@ -9,3 +9,11 @@ Docker, and consists of three components:
* A single-instance Redis master to store guestbook entries
* Multiple replicated Redis instances to serve reads
* Multiple web frontend instances
+
+In this directory, you will find two variants of the Guestbook:
+
+1. [simple/](./simple) is a straight port of the original YAML.
+2. [components](./components) demonstrates benefits of using a real language, namely eliminating boilerplate through
+ the use of real component abstractions.
+
+Both examples provision the exact same Kubernetes Guestbook application, but showcase different aspects of Pulumi.

ADD
kubernetes-py-guestbook/components/Pulumi.yaml
+name: kubernetes-py-guestbook
+runtime: python
+description: Kubernetes Guestbook example based on https://kubernetes.io/docs/tutorials/stateless-application/guestbook/

ADD
kubernetes-py-guestbook/components/__main__.py
+# Copyright 2016-2020, Pulumi Corporation.
+#
+# 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 pulumi
+from service_deployment import ServiceDeployment
+
+# Minikube does not implement services of type `LoadBalancer`; require the user to specify if we're
+# running on minikube, and if so, create only services of type ClusterIP.
+config = pulumi.Config()
+isMinikube = config.get_bool("isMinikube")
+
+ServiceDeployment(
+ "redis-master",
+ image="k8s.gcr.io/redis:e2e",
+ ports=[6379])
+ServiceDeployment(
+ "redis-slave",
+ image="gcr.io/google_samples/gb-redisslave:v1",
+ ports=[6379])
+frontend = ServiceDeployment(
+ "frontend",
+ image="gcr.io/google-samples/gb-frontend:v4",
+ replicas=3,
+ ports=[80],
+ allocate_ip_address=True,
+ is_minikube=config.get_bool("isMinikube"))
+
+pulumi.export("frontend_ip", frontend.ip_address)

ADD
kubernetes-py-guestbook/components/imgs/guestbook.png
kubernetes-py-guestbook/components/imgs/guestbook.png
Binary files /dev/null and b/kubernetes-py-guestbook/components/imgs/guestbook.png differ

ADD
kubernetes-py-guestbook/components/requirements.txt
+pulumi>=2.0.0,<3.0.0
+pulumi-kubernetes>=2.0.0,<3.0.0

ADD
kubernetes-py-guestbook/components/service_deployment.py
+# Copyright 2016-2020, Pulumi Corporation.
+#
+# 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.
+
+from typing import List
+
+import pulumi
+from pulumi import ResourceOptions, ComponentResource, Output
+from pulumi_kubernetes.apps.v1 import Deployment
+from pulumi_kubernetes.core.v1 import Service, Namespace
+
+
+class ServiceDeployment(ComponentResource):
+ deployment: Deployment
+ service: Service
+ ip_address: Output[str]
+
+ def __init__(self, name: str, image: str,
+ resources: dict = None, replicas: int = None,
+ ports: List[int] = None, allocate_ip_address: bool = None,
+ is_minikube: bool = None, opts: ResourceOptions = None):
+ super().__init__('k8sx:component:ServiceDeployment', name, {}, opts)
+
+ labels = {"app": name}
+ container = {
+ "name": name,
+ "image": image,
+ "resources": resources or {"requests": {"cpu": "100m", "memory": "100Mi"}},
+ "ports": [{"container_port": p} for p in ports] if ports else None,
+ }
+ self.deployment = Deployment(
+ name,
+ spec={
+ "selector": {"match_labels": labels},
+ "replicas": 1,
+ "template": {
+ "metadata": {"labels": labels},
+ "spec": {"containers": [container]},
+ },
+ },
+ opts=pulumi.ResourceOptions(parent=self))
+ self.service = Service(
+ name,
+ metadata={
+ "name": name,
+ "labels": self.deployment.metadata['labels'],
+ },
+ spec={
+ "ports": [{"port": p, "targetPort": p} for p in ports] if ports else None,
+ "selector": self.deployment.spec['template']['metadata']['labels'],
+ "type": ("ClusterIP" if is_minikube else "LoadBalancer") if allocate_ip_address else None,
+ },
+ opts=pulumi.ResourceOptions(parent=self))
+ if allocate_ip_address:
+ if is_minikube:
+ self.ip_address = self.service.spec['clusterIP']
+ else:
+ ingress=self.service.status['load_balancer']['ingress'][0]
+ self.ip_address = ingress.apply(lambda i: ingress["ip"] if "ip" in i else ingress['hostname'])
+ self.register_outputs({})
\ No newline at end of file

Add Python Guestbook Component Example (#689)