diff --git a/1 b/1 deleted file mode 100644 index d00491fd..00000000 --- a/1 +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..22836d5e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +# Copyright 2020 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. + +FROM python:3.10.8-slim@sha256:49749648f4426b31b20fca55ad854caa55ff59dc604f2f76b57d814e0a47c181 as base + +FROM base as builder + +RUN apt-get -qq update \ + && apt-get install -y --no-install-recommends \ + wget g++ \ + && rm -rf /var/lib/apt/lists/* + +# Download the grpc health probe +# renovate: datasource=github-releases depName=grpc-ecosystem/grpc-health-probe +ENV GRPC_HEALTH_PROBE_VERSION=v0.4.18 +RUN wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ + chmod +x /bin/grpc_health_probe + +# get packages +COPY requirements.txt . +RUN pip install -r requirements.txt + +FROM base as without-grpc-health-probe-bin +# Enable unbuffered logging +ENV PYTHONUNBUFFERED=1 +# Enable Profiler +ENV ENABLE_PROFILER=1 + +WORKDIR /email_server + +# Grab packages from builder +COPY --from=builder /usr/local/lib/python3.10/ /usr/local/lib/python3.10/ + +# Add the application +COPY . . + +EXPOSE 8080 +ENTRYPOINT [ "python", "email_server.py" ] + +FROM without-grpc-health-probe-bin + +COPY --from=builder /bin/grpc_health_probe /bin/grpc_health_probe \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..0728e572 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,25 @@ +pipeline { + agent any + + stages { + stage('Build & Tag Docker Image') { + steps { + script { + withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { + sh "docker build -t abhishek0768/emailservice:latest ." + } + } + } + } + + stage('Push Docker Image') { + steps { + script { + withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { + sh "docker push abhishek0768/emailservice:latest " + } + } + } + } + } +} diff --git a/demo_pb2.py b/demo_pb2.py new file mode 100644 index 00000000..fa7589f1 --- /dev/null +++ b/demo_pb2.py @@ -0,0 +1,121 @@ +#!/usr/bin/python +# +# 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. + +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: demo.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ndemo.proto\x12\x0bhipstershop\"0\n\x08\x43\x61rtItem\x12\x12\n\nproduct_id\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\x05\"F\n\x0e\x41\x64\x64ItemRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12#\n\x04item\x18\x02 \x01(\x0b\x32\x15.hipstershop.CartItem\"#\n\x10\x45mptyCartRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\"!\n\x0eGetCartRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\"=\n\x04\x43\x61rt\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12$\n\x05items\x18\x02 \x03(\x0b\x32\x15.hipstershop.CartItem\"\x07\n\x05\x45mpty\"B\n\x1aListRecommendationsRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x13\n\x0bproduct_ids\x18\x02 \x03(\t\"2\n\x1bListRecommendationsResponse\x12\x13\n\x0bproduct_ids\x18\x01 \x03(\t\"\x84\x01\n\x07Product\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x0f\n\x07picture\x18\x04 \x01(\t\x12%\n\tprice_usd\x18\x05 \x01(\x0b\x32\x12.hipstershop.Money\x12\x12\n\ncategories\x18\x06 \x03(\t\">\n\x14ListProductsResponse\x12&\n\x08products\x18\x01 \x03(\x0b\x32\x14.hipstershop.Product\"\x1f\n\x11GetProductRequest\x12\n\n\x02id\x18\x01 \x01(\t\"&\n\x15SearchProductsRequest\x12\r\n\x05query\x18\x01 \x01(\t\"?\n\x16SearchProductsResponse\x12%\n\x07results\x18\x01 \x03(\x0b\x32\x14.hipstershop.Product\"^\n\x0fGetQuoteRequest\x12%\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32\x14.hipstershop.Address\x12$\n\x05items\x18\x02 \x03(\x0b\x32\x15.hipstershop.CartItem\"8\n\x10GetQuoteResponse\x12$\n\x08\x63ost_usd\x18\x01 \x01(\x0b\x32\x12.hipstershop.Money\"_\n\x10ShipOrderRequest\x12%\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32\x14.hipstershop.Address\x12$\n\x05items\x18\x02 \x03(\x0b\x32\x15.hipstershop.CartItem\"(\n\x11ShipOrderResponse\x12\x13\n\x0btracking_id\x18\x01 \x01(\t\"a\n\x07\x41\x64\x64ress\x12\x16\n\x0estreet_address\x18\x01 \x01(\t\x12\x0c\n\x04\x63ity\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x04 \x01(\t\x12\x10\n\x08zip_code\x18\x05 \x01(\x05\"<\n\x05Money\x12\x15\n\rcurrency_code\x18\x01 \x01(\t\x12\r\n\x05units\x18\x02 \x01(\x03\x12\r\n\x05nanos\x18\x03 \x01(\x05\"8\n\x1eGetSupportedCurrenciesResponse\x12\x16\n\x0e\x63urrency_codes\x18\x01 \x03(\t\"N\n\x19\x43urrencyConversionRequest\x12 \n\x04\x66rom\x18\x01 \x01(\x0b\x32\x12.hipstershop.Money\x12\x0f\n\x07to_code\x18\x02 \x01(\t\"\x90\x01\n\x0e\x43reditCardInfo\x12\x1a\n\x12\x63redit_card_number\x18\x01 \x01(\t\x12\x17\n\x0f\x63redit_card_cvv\x18\x02 \x01(\x05\x12#\n\x1b\x63redit_card_expiration_year\x18\x03 \x01(\x05\x12$\n\x1c\x63redit_card_expiration_month\x18\x04 \x01(\x05\"e\n\rChargeRequest\x12\"\n\x06\x61mount\x18\x01 \x01(\x0b\x32\x12.hipstershop.Money\x12\x30\n\x0b\x63redit_card\x18\x02 \x01(\x0b\x32\x1b.hipstershop.CreditCardInfo\"(\n\x0e\x43hargeResponse\x12\x16\n\x0etransaction_id\x18\x01 \x01(\t\"R\n\tOrderItem\x12#\n\x04item\x18\x01 \x01(\x0b\x32\x15.hipstershop.CartItem\x12 \n\x04\x63ost\x18\x02 \x01(\x0b\x32\x12.hipstershop.Money\"\xbf\x01\n\x0bOrderResult\x12\x10\n\x08order_id\x18\x01 \x01(\t\x12\x1c\n\x14shipping_tracking_id\x18\x02 \x01(\t\x12)\n\rshipping_cost\x18\x03 \x01(\x0b\x32\x12.hipstershop.Money\x12.\n\x10shipping_address\x18\x04 \x01(\x0b\x32\x14.hipstershop.Address\x12%\n\x05items\x18\x05 \x03(\x0b\x32\x16.hipstershop.OrderItem\"V\n\x1cSendOrderConfirmationRequest\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\'\n\x05order\x18\x02 \x01(\x0b\x32\x18.hipstershop.OrderResult\"\xa3\x01\n\x11PlaceOrderRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x15\n\ruser_currency\x18\x02 \x01(\t\x12%\n\x07\x61\x64\x64ress\x18\x03 \x01(\x0b\x32\x14.hipstershop.Address\x12\r\n\x05\x65mail\x18\x05 \x01(\t\x12\x30\n\x0b\x63redit_card\x18\x06 \x01(\x0b\x32\x1b.hipstershop.CreditCardInfo\"=\n\x12PlaceOrderResponse\x12\'\n\x05order\x18\x01 \x01(\x0b\x32\x18.hipstershop.OrderResult\"!\n\tAdRequest\x12\x14\n\x0c\x63ontext_keys\x18\x01 \x03(\t\"*\n\nAdResponse\x12\x1c\n\x03\x61\x64s\x18\x01 \x03(\x0b\x32\x0f.hipstershop.Ad\"(\n\x02\x41\x64\x12\x14\n\x0credirect_url\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t2\xca\x01\n\x0b\x43\x61rtService\x12<\n\x07\x41\x64\x64Item\x12\x1b.hipstershop.AddItemRequest\x1a\x12.hipstershop.Empty\"\x00\x12;\n\x07GetCart\x12\x1b.hipstershop.GetCartRequest\x1a\x11.hipstershop.Cart\"\x00\x12@\n\tEmptyCart\x12\x1d.hipstershop.EmptyCartRequest\x1a\x12.hipstershop.Empty\"\x00\x32\x83\x01\n\x15RecommendationService\x12j\n\x13ListRecommendations\x12\'.hipstershop.ListRecommendationsRequest\x1a(.hipstershop.ListRecommendationsResponse\"\x00\x32\x83\x02\n\x15ProductCatalogService\x12G\n\x0cListProducts\x12\x12.hipstershop.Empty\x1a!.hipstershop.ListProductsResponse\"\x00\x12\x44\n\nGetProduct\x12\x1e.hipstershop.GetProductRequest\x1a\x14.hipstershop.Product\"\x00\x12[\n\x0eSearchProducts\x12\".hipstershop.SearchProductsRequest\x1a#.hipstershop.SearchProductsResponse\"\x00\x32\xaa\x01\n\x0fShippingService\x12I\n\x08GetQuote\x12\x1c.hipstershop.GetQuoteRequest\x1a\x1d.hipstershop.GetQuoteResponse\"\x00\x12L\n\tShipOrder\x12\x1d.hipstershop.ShipOrderRequest\x1a\x1e.hipstershop.ShipOrderResponse\"\x00\x32\xb7\x01\n\x0f\x43urrencyService\x12[\n\x16GetSupportedCurrencies\x12\x12.hipstershop.Empty\x1a+.hipstershop.GetSupportedCurrenciesResponse\"\x00\x12G\n\x07\x43onvert\x12&.hipstershop.CurrencyConversionRequest\x1a\x12.hipstershop.Money\"\x00\x32U\n\x0ePaymentService\x12\x43\n\x06\x43harge\x12\x1a.hipstershop.ChargeRequest\x1a\x1b.hipstershop.ChargeResponse\"\x00\x32h\n\x0c\x45mailService\x12X\n\x15SendOrderConfirmation\x12).hipstershop.SendOrderConfirmationRequest\x1a\x12.hipstershop.Empty\"\x00\x32\x62\n\x0f\x43heckoutService\x12O\n\nPlaceOrder\x12\x1e.hipstershop.PlaceOrderRequest\x1a\x1f.hipstershop.PlaceOrderResponse\"\x00\x32H\n\tAdService\x12;\n\x06GetAds\x12\x16.hipstershop.AdRequest\x1a\x17.hipstershop.AdResponse\"\x00\x62\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'demo_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _CARTITEM._serialized_start=27 + _CARTITEM._serialized_end=75 + _ADDITEMREQUEST._serialized_start=77 + _ADDITEMREQUEST._serialized_end=147 + _EMPTYCARTREQUEST._serialized_start=149 + _EMPTYCARTREQUEST._serialized_end=184 + _GETCARTREQUEST._serialized_start=186 + _GETCARTREQUEST._serialized_end=219 + _CART._serialized_start=221 + _CART._serialized_end=282 + _EMPTY._serialized_start=284 + _EMPTY._serialized_end=291 + _LISTRECOMMENDATIONSREQUEST._serialized_start=293 + _LISTRECOMMENDATIONSREQUEST._serialized_end=359 + _LISTRECOMMENDATIONSRESPONSE._serialized_start=361 + _LISTRECOMMENDATIONSRESPONSE._serialized_end=411 + _PRODUCT._serialized_start=414 + _PRODUCT._serialized_end=546 + _LISTPRODUCTSRESPONSE._serialized_start=548 + _LISTPRODUCTSRESPONSE._serialized_end=610 + _GETPRODUCTREQUEST._serialized_start=612 + _GETPRODUCTREQUEST._serialized_end=643 + _SEARCHPRODUCTSREQUEST._serialized_start=645 + _SEARCHPRODUCTSREQUEST._serialized_end=683 + _SEARCHPRODUCTSRESPONSE._serialized_start=685 + _SEARCHPRODUCTSRESPONSE._serialized_end=748 + _GETQUOTEREQUEST._serialized_start=750 + _GETQUOTEREQUEST._serialized_end=844 + _GETQUOTERESPONSE._serialized_start=846 + _GETQUOTERESPONSE._serialized_end=902 + _SHIPORDERREQUEST._serialized_start=904 + _SHIPORDERREQUEST._serialized_end=999 + _SHIPORDERRESPONSE._serialized_start=1001 + _SHIPORDERRESPONSE._serialized_end=1041 + _ADDRESS._serialized_start=1043 + _ADDRESS._serialized_end=1140 + _MONEY._serialized_start=1142 + _MONEY._serialized_end=1202 + _GETSUPPORTEDCURRENCIESRESPONSE._serialized_start=1204 + _GETSUPPORTEDCURRENCIESRESPONSE._serialized_end=1260 + _CURRENCYCONVERSIONREQUEST._serialized_start=1262 + _CURRENCYCONVERSIONREQUEST._serialized_end=1340 + _CREDITCARDINFO._serialized_start=1343 + _CREDITCARDINFO._serialized_end=1487 + _CHARGEREQUEST._serialized_start=1489 + _CHARGEREQUEST._serialized_end=1590 + _CHARGERESPONSE._serialized_start=1592 + _CHARGERESPONSE._serialized_end=1632 + _ORDERITEM._serialized_start=1634 + _ORDERITEM._serialized_end=1716 + _ORDERRESULT._serialized_start=1719 + _ORDERRESULT._serialized_end=1910 + _SENDORDERCONFIRMATIONREQUEST._serialized_start=1912 + _SENDORDERCONFIRMATIONREQUEST._serialized_end=1998 + _PLACEORDERREQUEST._serialized_start=2001 + _PLACEORDERREQUEST._serialized_end=2164 + _PLACEORDERRESPONSE._serialized_start=2166 + _PLACEORDERRESPONSE._serialized_end=2227 + _ADREQUEST._serialized_start=2229 + _ADREQUEST._serialized_end=2262 + _ADRESPONSE._serialized_start=2264 + _ADRESPONSE._serialized_end=2306 + _AD._serialized_start=2308 + _AD._serialized_end=2348 + _CARTSERVICE._serialized_start=2351 + _CARTSERVICE._serialized_end=2553 + _RECOMMENDATIONSERVICE._serialized_start=2556 + _RECOMMENDATIONSERVICE._serialized_end=2687 + _PRODUCTCATALOGSERVICE._serialized_start=2690 + _PRODUCTCATALOGSERVICE._serialized_end=2949 + _SHIPPINGSERVICE._serialized_start=2952 + _SHIPPINGSERVICE._serialized_end=3122 + _CURRENCYSERVICE._serialized_start=3125 + _CURRENCYSERVICE._serialized_end=3308 + _PAYMENTSERVICE._serialized_start=3310 + _PAYMENTSERVICE._serialized_end=3395 + _EMAILSERVICE._serialized_start=3397 + _EMAILSERVICE._serialized_end=3501 + _CHECKOUTSERVICE._serialized_start=3503 + _CHECKOUTSERVICE._serialized_end=3601 + _ADSERVICE._serialized_start=3603 + _ADSERVICE._serialized_end=3675 +# @@protoc_insertion_point(module_scope) diff --git a/demo_pb2_grpc.py b/demo_pb2_grpc.py new file mode 100644 index 00000000..47bbf0a9 --- /dev/null +++ b/demo_pb2_grpc.py @@ -0,0 +1,822 @@ +#!/usr/bin/python +# +# 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 the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import demo_pb2 as demo__pb2 + + +class CartServiceStub(object): + """-----------------Cart service----------------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.AddItem = channel.unary_unary( + '/hipstershop.CartService/AddItem', + request_serializer=demo__pb2.AddItemRequest.SerializeToString, + response_deserializer=demo__pb2.Empty.FromString, + ) + self.GetCart = channel.unary_unary( + '/hipstershop.CartService/GetCart', + request_serializer=demo__pb2.GetCartRequest.SerializeToString, + response_deserializer=demo__pb2.Cart.FromString, + ) + self.EmptyCart = channel.unary_unary( + '/hipstershop.CartService/EmptyCart', + request_serializer=demo__pb2.EmptyCartRequest.SerializeToString, + response_deserializer=demo__pb2.Empty.FromString, + ) + + +class CartServiceServicer(object): + """-----------------Cart service----------------- + + """ + + def AddItem(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetCart(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def EmptyCart(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_CartServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'AddItem': grpc.unary_unary_rpc_method_handler( + servicer.AddItem, + request_deserializer=demo__pb2.AddItemRequest.FromString, + response_serializer=demo__pb2.Empty.SerializeToString, + ), + 'GetCart': grpc.unary_unary_rpc_method_handler( + servicer.GetCart, + request_deserializer=demo__pb2.GetCartRequest.FromString, + response_serializer=demo__pb2.Cart.SerializeToString, + ), + 'EmptyCart': grpc.unary_unary_rpc_method_handler( + servicer.EmptyCart, + request_deserializer=demo__pb2.EmptyCartRequest.FromString, + response_serializer=demo__pb2.Empty.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.CartService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class CartService(object): + """-----------------Cart service----------------- + + """ + + @staticmethod + def AddItem(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.CartService/AddItem', + demo__pb2.AddItemRequest.SerializeToString, + demo__pb2.Empty.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetCart(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.CartService/GetCart', + demo__pb2.GetCartRequest.SerializeToString, + demo__pb2.Cart.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def EmptyCart(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.CartService/EmptyCart', + demo__pb2.EmptyCartRequest.SerializeToString, + demo__pb2.Empty.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class RecommendationServiceStub(object): + """---------------Recommendation service---------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.ListRecommendations = channel.unary_unary( + '/hipstershop.RecommendationService/ListRecommendations', + request_serializer=demo__pb2.ListRecommendationsRequest.SerializeToString, + response_deserializer=demo__pb2.ListRecommendationsResponse.FromString, + ) + + +class RecommendationServiceServicer(object): + """---------------Recommendation service---------- + + """ + + def ListRecommendations(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_RecommendationServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'ListRecommendations': grpc.unary_unary_rpc_method_handler( + servicer.ListRecommendations, + request_deserializer=demo__pb2.ListRecommendationsRequest.FromString, + response_serializer=demo__pb2.ListRecommendationsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.RecommendationService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class RecommendationService(object): + """---------------Recommendation service---------- + + """ + + @staticmethod + def ListRecommendations(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.RecommendationService/ListRecommendations', + demo__pb2.ListRecommendationsRequest.SerializeToString, + demo__pb2.ListRecommendationsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class ProductCatalogServiceStub(object): + """---------------Product Catalog---------------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.ListProducts = channel.unary_unary( + '/hipstershop.ProductCatalogService/ListProducts', + request_serializer=demo__pb2.Empty.SerializeToString, + response_deserializer=demo__pb2.ListProductsResponse.FromString, + ) + self.GetProduct = channel.unary_unary( + '/hipstershop.ProductCatalogService/GetProduct', + request_serializer=demo__pb2.GetProductRequest.SerializeToString, + response_deserializer=demo__pb2.Product.FromString, + ) + self.SearchProducts = channel.unary_unary( + '/hipstershop.ProductCatalogService/SearchProducts', + request_serializer=demo__pb2.SearchProductsRequest.SerializeToString, + response_deserializer=demo__pb2.SearchProductsResponse.FromString, + ) + + +class ProductCatalogServiceServicer(object): + """---------------Product Catalog---------------- + + """ + + def ListProducts(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetProduct(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def SearchProducts(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_ProductCatalogServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'ListProducts': grpc.unary_unary_rpc_method_handler( + servicer.ListProducts, + request_deserializer=demo__pb2.Empty.FromString, + response_serializer=demo__pb2.ListProductsResponse.SerializeToString, + ), + 'GetProduct': grpc.unary_unary_rpc_method_handler( + servicer.GetProduct, + request_deserializer=demo__pb2.GetProductRequest.FromString, + response_serializer=demo__pb2.Product.SerializeToString, + ), + 'SearchProducts': grpc.unary_unary_rpc_method_handler( + servicer.SearchProducts, + request_deserializer=demo__pb2.SearchProductsRequest.FromString, + response_serializer=demo__pb2.SearchProductsResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.ProductCatalogService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class ProductCatalogService(object): + """---------------Product Catalog---------------- + + """ + + @staticmethod + def ListProducts(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.ProductCatalogService/ListProducts', + demo__pb2.Empty.SerializeToString, + demo__pb2.ListProductsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetProduct(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.ProductCatalogService/GetProduct', + demo__pb2.GetProductRequest.SerializeToString, + demo__pb2.Product.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def SearchProducts(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.ProductCatalogService/SearchProducts', + demo__pb2.SearchProductsRequest.SerializeToString, + demo__pb2.SearchProductsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class ShippingServiceStub(object): + """---------------Shipping Service---------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetQuote = channel.unary_unary( + '/hipstershop.ShippingService/GetQuote', + request_serializer=demo__pb2.GetQuoteRequest.SerializeToString, + response_deserializer=demo__pb2.GetQuoteResponse.FromString, + ) + self.ShipOrder = channel.unary_unary( + '/hipstershop.ShippingService/ShipOrder', + request_serializer=demo__pb2.ShipOrderRequest.SerializeToString, + response_deserializer=demo__pb2.ShipOrderResponse.FromString, + ) + + +class ShippingServiceServicer(object): + """---------------Shipping Service---------- + + """ + + def GetQuote(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ShipOrder(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_ShippingServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetQuote': grpc.unary_unary_rpc_method_handler( + servicer.GetQuote, + request_deserializer=demo__pb2.GetQuoteRequest.FromString, + response_serializer=demo__pb2.GetQuoteResponse.SerializeToString, + ), + 'ShipOrder': grpc.unary_unary_rpc_method_handler( + servicer.ShipOrder, + request_deserializer=demo__pb2.ShipOrderRequest.FromString, + response_serializer=demo__pb2.ShipOrderResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.ShippingService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class ShippingService(object): + """---------------Shipping Service---------- + + """ + + @staticmethod + def GetQuote(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.ShippingService/GetQuote', + demo__pb2.GetQuoteRequest.SerializeToString, + demo__pb2.GetQuoteResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def ShipOrder(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.ShippingService/ShipOrder', + demo__pb2.ShipOrderRequest.SerializeToString, + demo__pb2.ShipOrderResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class CurrencyServiceStub(object): + """-----------------Currency service----------------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetSupportedCurrencies = channel.unary_unary( + '/hipstershop.CurrencyService/GetSupportedCurrencies', + request_serializer=demo__pb2.Empty.SerializeToString, + response_deserializer=demo__pb2.GetSupportedCurrenciesResponse.FromString, + ) + self.Convert = channel.unary_unary( + '/hipstershop.CurrencyService/Convert', + request_serializer=demo__pb2.CurrencyConversionRequest.SerializeToString, + response_deserializer=demo__pb2.Money.FromString, + ) + + +class CurrencyServiceServicer(object): + """-----------------Currency service----------------- + + """ + + def GetSupportedCurrencies(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Convert(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_CurrencyServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetSupportedCurrencies': grpc.unary_unary_rpc_method_handler( + servicer.GetSupportedCurrencies, + request_deserializer=demo__pb2.Empty.FromString, + response_serializer=demo__pb2.GetSupportedCurrenciesResponse.SerializeToString, + ), + 'Convert': grpc.unary_unary_rpc_method_handler( + servicer.Convert, + request_deserializer=demo__pb2.CurrencyConversionRequest.FromString, + response_serializer=demo__pb2.Money.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.CurrencyService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class CurrencyService(object): + """-----------------Currency service----------------- + + """ + + @staticmethod + def GetSupportedCurrencies(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.CurrencyService/GetSupportedCurrencies', + demo__pb2.Empty.SerializeToString, + demo__pb2.GetSupportedCurrenciesResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def Convert(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.CurrencyService/Convert', + demo__pb2.CurrencyConversionRequest.SerializeToString, + demo__pb2.Money.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class PaymentServiceStub(object): + """-------------Payment service----------------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Charge = channel.unary_unary( + '/hipstershop.PaymentService/Charge', + request_serializer=demo__pb2.ChargeRequest.SerializeToString, + response_deserializer=demo__pb2.ChargeResponse.FromString, + ) + + +class PaymentServiceServicer(object): + """-------------Payment service----------------- + + """ + + def Charge(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_PaymentServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Charge': grpc.unary_unary_rpc_method_handler( + servicer.Charge, + request_deserializer=demo__pb2.ChargeRequest.FromString, + response_serializer=demo__pb2.ChargeResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.PaymentService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class PaymentService(object): + """-------------Payment service----------------- + + """ + + @staticmethod + def Charge(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.PaymentService/Charge', + demo__pb2.ChargeRequest.SerializeToString, + demo__pb2.ChargeResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class EmailServiceStub(object): + """-------------Email service----------------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.SendOrderConfirmation = channel.unary_unary( + '/hipstershop.EmailService/SendOrderConfirmation', + request_serializer=demo__pb2.SendOrderConfirmationRequest.SerializeToString, + response_deserializer=demo__pb2.Empty.FromString, + ) + + +class EmailServiceServicer(object): + """-------------Email service----------------- + + """ + + def SendOrderConfirmation(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_EmailServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SendOrderConfirmation': grpc.unary_unary_rpc_method_handler( + servicer.SendOrderConfirmation, + request_deserializer=demo__pb2.SendOrderConfirmationRequest.FromString, + response_serializer=demo__pb2.Empty.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.EmailService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class EmailService(object): + """-------------Email service----------------- + + """ + + @staticmethod + def SendOrderConfirmation(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.EmailService/SendOrderConfirmation', + demo__pb2.SendOrderConfirmationRequest.SerializeToString, + demo__pb2.Empty.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class CheckoutServiceStub(object): + """-------------Checkout service----------------- + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.PlaceOrder = channel.unary_unary( + '/hipstershop.CheckoutService/PlaceOrder', + request_serializer=demo__pb2.PlaceOrderRequest.SerializeToString, + response_deserializer=demo__pb2.PlaceOrderResponse.FromString, + ) + + +class CheckoutServiceServicer(object): + """-------------Checkout service----------------- + + """ + + def PlaceOrder(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_CheckoutServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'PlaceOrder': grpc.unary_unary_rpc_method_handler( + servicer.PlaceOrder, + request_deserializer=demo__pb2.PlaceOrderRequest.FromString, + response_serializer=demo__pb2.PlaceOrderResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.CheckoutService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class CheckoutService(object): + """-------------Checkout service----------------- + + """ + + @staticmethod + def PlaceOrder(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.CheckoutService/PlaceOrder', + demo__pb2.PlaceOrderRequest.SerializeToString, + demo__pb2.PlaceOrderResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + +class AdServiceStub(object): + """------------Ad service------------------ + + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetAds = channel.unary_unary( + '/hipstershop.AdService/GetAds', + request_serializer=demo__pb2.AdRequest.SerializeToString, + response_deserializer=demo__pb2.AdResponse.FromString, + ) + + +class AdServiceServicer(object): + """------------Ad service------------------ + + """ + + def GetAds(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_AdServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetAds': grpc.unary_unary_rpc_method_handler( + servicer.GetAds, + request_deserializer=demo__pb2.AdRequest.FromString, + response_serializer=demo__pb2.AdResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hipstershop.AdService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class AdService(object): + """------------Ad service------------------ + + """ + + @staticmethod + def GetAds(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hipstershop.AdService/GetAds', + demo__pb2.AdRequest.SerializeToString, + demo__pb2.AdResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/email_client.py b/email_client.py new file mode 100644 index 00000000..4411ca00 --- /dev/null +++ b/email_client.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +# +# 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 +# +# 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 grpc + +import demo_pb2 +import demo_pb2_grpc + +from logger import getJSONLogger +logger = getJSONLogger('emailservice-client') + +def send_confirmation_email(email, order): + channel = grpc.insecure_channel('[::]:8080') + stub = demo_pb2_grpc.EmailServiceStub(channel) + try: + response = stub.SendOrderConfirmation(demo_pb2.SendOrderConfirmationRequest( + email = email, + order = order + )) + logger.info('Request sent.') + except grpc.RpcError as err: + logger.error(err.details()) + logger.error('{}, {}'.format(err.code().name, err.code().value)) + +if __name__ == '__main__': + logger.info('Client for email service.') diff --git a/email_server.py b/email_server.py new file mode 100644 index 00000000..b4983189 --- /dev/null +++ b/email_server.py @@ -0,0 +1,198 @@ +#!/usr/bin/python +# +# 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 +# +# 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 concurrent import futures +import argparse +import os +import sys +import time +import grpc +import traceback +from jinja2 import Environment, FileSystemLoader, select_autoescape, TemplateError +from google.api_core.exceptions import GoogleAPICallError +from google.auth.exceptions import DefaultCredentialsError + +import demo_pb2 +import demo_pb2_grpc +from grpc_health.v1 import health_pb2 +from grpc_health.v1 import health_pb2_grpc + +from opentelemetry import trace +from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import BatchSpanProcessor +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter + +import googlecloudprofiler + +from logger import getJSONLogger +logger = getJSONLogger('emailservice-server') + +# Loads confirmation email template from file +env = Environment( + loader=FileSystemLoader('templates'), + autoescape=select_autoescape(['html', 'xml']) +) +template = env.get_template('confirmation.html') + +class BaseEmailService(demo_pb2_grpc.EmailServiceServicer): + def Check(self, request, context): + return health_pb2.HealthCheckResponse( + status=health_pb2.HealthCheckResponse.SERVING) + + def Watch(self, request, context): + return health_pb2.HealthCheckResponse( + status=health_pb2.HealthCheckResponse.UNIMPLEMENTED) + +class EmailService(BaseEmailService): + def __init__(self): + raise Exception('cloud mail client not implemented') + super().__init__() + + @staticmethod + def send_email(client, email_address, content): + response = client.send_message( + sender = client.sender_path(project_id, region, sender_id), + envelope_from_authority = '', + header_from_authority = '', + envelope_from_address = from_address, + simple_message = { + "from": { + "address_spec": from_address, + }, + "to": [{ + "address_spec": email_address + }], + "subject": "Your Confirmation Email", + "html_body": content + } + ) + logger.info("Message sent: {}".format(response.rfc822_message_id)) + + def SendOrderConfirmation(self, request, context): + email = request.email + order = request.order + + try: + confirmation = template.render(order = order) + except TemplateError as err: + context.set_details("An error occurred when preparing the confirmation mail.") + logger.error(err.message) + context.set_code(grpc.StatusCode.INTERNAL) + return demo_pb2.Empty() + + try: + EmailService.send_email(self.client, email, confirmation) + except GoogleAPICallError as err: + context.set_details("An error occurred when sending the email.") + print(err.message) + context.set_code(grpc.StatusCode.INTERNAL) + return demo_pb2.Empty() + + return demo_pb2.Empty() + +class DummyEmailService(BaseEmailService): + def SendOrderConfirmation(self, request, context): + logger.info('A request to send order confirmation email to {} has been received.'.format(request.email)) + return demo_pb2.Empty() + +class HealthCheck(): + def Check(self, request, context): + return health_pb2.HealthCheckResponse( + status=health_pb2.HealthCheckResponse.SERVING) + +def start(dummy_mode): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10),) + service = None + if dummy_mode: + service = DummyEmailService() + else: + raise Exception('non-dummy mode not implemented yet') + + demo_pb2_grpc.add_EmailServiceServicer_to_server(service, server) + health_pb2_grpc.add_HealthServicer_to_server(service, server) + + port = os.environ.get('PORT', "8080") + logger.info("listening on port: "+port) + server.add_insecure_port('[::]:'+port) + server.start() + try: + while True: + time.sleep(3600) + except KeyboardInterrupt: + server.stop(0) + +def initStackdriverProfiling(): + project_id = None + try: + project_id = os.environ["GCP_PROJECT_ID"] + except KeyError: + # Environment variable not set + pass + + for retry in range(1,4): + try: + if project_id: + googlecloudprofiler.start(service='email_server', service_version='1.0.0', verbose=0, project_id=project_id) + else: + googlecloudprofiler.start(service='email_server', service_version='1.0.0', verbose=0) + logger.info("Successfully started Stackdriver Profiler.") + return + except (BaseException) as exc: + logger.info("Unable to start Stackdriver Profiler Python agent. " + str(exc)) + if (retry < 4): + logger.info("Sleeping %d to retry initializing Stackdriver Profiler"%(retry*10)) + time.sleep (1) + else: + logger.warning("Could not initialize Stackdriver Profiler after retrying, giving up") + return + + +if __name__ == '__main__': + logger.info('starting the email service in dummy mode.') + + # Profiler + try: + if "DISABLE_PROFILER" in os.environ: + raise KeyError() + else: + logger.info("Profiler enabled.") + initStackdriverProfiling() + except KeyError: + logger.info("Profiler disabled.") + + # Tracing + try: + if os.environ["ENABLE_TRACING"] == "1": + otel_endpoint = os.getenv("COLLECTOR_SERVICE_ADDR", "localhost:4317") + trace.set_tracer_provider(TracerProvider()) + trace.get_tracer_provider().add_span_processor( + BatchSpanProcessor( + OTLPSpanExporter( + endpoint = otel_endpoint, + insecure = True + ) + ) + ) + grpc_server_instrumentor = GrpcInstrumentorServer() + grpc_server_instrumentor.instrument() + + except (KeyError, DefaultCredentialsError): + logger.info("Tracing disabled.") + except Exception as e: + logger.warn(f"Exception on Cloud Trace setup: {traceback.format_exc()}, tracing disabled.") + + start(dummy_mode = True) diff --git a/genproto.sh b/genproto.sh new file mode 100644 index 00000000..f67056a3 --- /dev/null +++ b/genproto.sh @@ -0,0 +1,21 @@ +#!/bin/bash -eu +# +# 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 +# +# 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. + +# [START gke_emailservice_genproto] + +python -m grpc_tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/demo.proto + +# [END gke_emailservice_genproto] \ No newline at end of file diff --git a/logger.py b/logger.py new file mode 100644 index 00000000..dc849100 --- /dev/null +++ b/logger.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# +# 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 +# +# 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 logging +import sys +from pythonjsonlogger import jsonlogger + +# TODO(yoshifumi) this class is duplicated since other Python services are +# not sharing the modules for logging. +class CustomJsonFormatter(jsonlogger.JsonFormatter): + def add_fields(self, log_record, record, message_dict): + super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict) + if not log_record.get('timestamp'): + log_record['timestamp'] = record.created + if log_record.get('severity'): + log_record['severity'] = log_record['severity'].upper() + else: + log_record['severity'] = record.levelname + +def getJSONLogger(name): + logger = logging.getLogger(name) + handler = logging.StreamHandler(sys.stdout) + formatter = CustomJsonFormatter('%(timestamp)s %(severity)s %(name)s %(message)s') + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + logger.propagate = False + return logger diff --git a/requirements.in b/requirements.in new file mode 100644 index 00000000..cdf0e2ca --- /dev/null +++ b/requirements.in @@ -0,0 +1,11 @@ +google-api-core==2.11.0 +grpcio-health-checking==1.54.0 +grpcio==1.54.0 +jinja2==3.1.2 +python-json-logger==2.0.7 +google-cloud-profiler==4.0.0 +google-cloud-trace==1.11.1 +requests==2.30.0 +opentelemetry-distro==0.38b0 +opentelemetry-instrumentation-grpc==0.38b0 +opentelemetry-exporter-otlp-proto-grpc==1.17.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..24ff6a7f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,142 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --output-file=requirements.txt requirements.in +# +backoff==2.2.1 + # via opentelemetry-exporter-otlp-proto-grpc +cachetools==5.3.0 + # via google-auth +certifi==2022.12.7 + # via requests +charset-normalizer==3.1.0 + # via requests +deprecated==1.2.13 + # via opentelemetry-api +google-api-core[grpc]==2.11.0 + # via + # -r requirements.in + # google-api-python-client + # google-cloud-trace +google-api-python-client==2.86.0 + # via google-cloud-profiler +google-auth==2.18.1 + # via + # google-api-core + # google-api-python-client + # google-auth-httplib2 + # google-cloud-profiler +google-auth-httplib2==0.1.0 + # via + # google-api-python-client + # google-cloud-profiler +google-cloud-profiler==4.0.0 + # via -r requirements.in +google-cloud-trace==1.11.1 + # via -r requirements.in +googleapis-common-protos==1.59.0 + # via + # google-api-core + # grpcio-status + # opentelemetry-exporter-otlp-proto-grpc +grpcio==1.54.0 + # via + # -r requirements.in + # google-api-core + # grpcio-health-checking + # grpcio-status + # opentelemetry-exporter-otlp-proto-grpc +grpcio-health-checking==1.54.0 + # via -r requirements.in +grpcio-status==1.54.0 + # via google-api-core +httplib2==0.22.0 + # via + # google-api-python-client + # google-auth-httplib2 +idna==3.4 + # via requests +importlib-metadata==6.0.1 + # via opentelemetry-api +jinja2==3.1.2 + # via -r requirements.in +markupsafe==2.1.2 + # via jinja2 +opentelemetry-api==1.17.0 + # via + # opentelemetry-distro + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-instrumentation + # opentelemetry-instrumentation-grpc + # opentelemetry-sdk +opentelemetry-distro==0.38b0 + # via -r requirements.in +opentelemetry-exporter-otlp-proto-grpc==1.17.0 + # via -r requirements.in +opentelemetry-instrumentation==0.38b0 + # via + # opentelemetry-distro + # opentelemetry-instrumentation-grpc +opentelemetry-instrumentation-grpc==0.38b0 + # via -r requirements.in +opentelemetry-proto==1.17.0 + # via opentelemetry-exporter-otlp-proto-grpc +opentelemetry-sdk==1.17.0 + # via + # opentelemetry-distro + # opentelemetry-exporter-otlp-proto-grpc + # opentelemetry-instrumentation-grpc +opentelemetry-semantic-conventions==0.38b0 + # via + # opentelemetry-instrumentation-grpc + # opentelemetry-sdk +proto-plus==1.22.2 + # via google-cloud-trace +protobuf==4.23.0 + # via + # google-api-core + # google-cloud-profiler + # google-cloud-trace + # googleapis-common-protos + # grpcio-health-checking + # grpcio-status + # opentelemetry-proto + # proto-plus +pyasn1==0.5.0 + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.3.0 + # via google-auth +pyparsing==3.0.9 + # via httplib2 +python-json-logger==2.0.7 + # via -r requirements.in +requests==2.30.0 + # via + # -r requirements.in + # google-api-core + # google-cloud-profiler +rsa==4.9 + # via google-auth +six==1.16.0 + # via + # google-auth + # google-auth-httplib2 +typing-extensions==4.5.0 + # via opentelemetry-sdk +uritemplate==4.1.1 + # via google-api-python-client +urllib3==1.26.15 + # via requests +wrapt==1.15.0 + # via + # deprecated + # opentelemetry-instrumentation + # opentelemetry-instrumentation-grpc +zipp==3.15.0 + # via importlib-metadata + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/templates/confirmation.html b/templates/confirmation.html new file mode 100644 index 00000000..b6557450 --- /dev/null +++ b/templates/confirmation.html @@ -0,0 +1,53 @@ + + + + + + Your Order Confirmation + + + + +

Your Order Confirmation

+

Thanks for shopping with us!

+

Order ID

+

#{{ order.order_id }}

+

Shipping

+

#{{ order.shipping_tracking_id }}

+

{{ order.shipping_cost.units }}. {{ "%02d" | format(order.shipping_cost.nanos // 10000000) }} {{ order.shipping_cost.currency_code }}

+

{{ order.shipping_address.street_address_1 }}, {{order.shipping_address.street_address_2}}, {{order.shipping_address.city}}, {{order.shipping_address.country}} {{order.shipping_address.zip_code}}

+

Items

+ + + + + + + {% for item in order.items %} + + + + + + {% endfor %} +
Item No.QuantityPrice
#{{ item.item.product_id }}{{ item.item.quantity }}{{ item.cost.units }}.{{ "%02d" | format(item.cost.nanos // 10000000) }} {{ item.cost.currency_code }}
+ +