Initial commit
Some checks failed
Continuous Integration - Pull Request / code-tests (pull_request) Has been cancelled
Continuous Integration - Pull Request / deployment-tests (local-code) (pull_request) Has been cancelled
helm-chart-ci / helm-chart-ci (pull_request) Has been cancelled
kubevious-manifests-ci / kubevious-manifests-ci (pull_request) Has been cancelled
kustomize-build-ci / kustomize-build-ci (pull_request) Has been cancelled
terraform-validate-ci / terraform-validate-ci (pull_request) Has been cancelled
Clean up deployment / cleanup-namespace (pull_request) Has been cancelled
Continuous Integration - Main/Release / code-tests (push) Has been cancelled
Continuous Integration - Main/Release / deployment-tests (local-code) (push) Has been cancelled
helm-chart-ci / helm-chart-ci (push) Has been cancelled
kubevious-manifests-ci / kubevious-manifests-ci (push) Has been cancelled
kustomize-build-ci / kustomize-build-ci (push) Has been cancelled
terraform-validate-ci / terraform-validate-ci (push) Has been cancelled

This commit is contained in:
2026-02-04 20:47:56 +05:30
commit dafcd9777f
363 changed files with 52703 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
# 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 --platform=$BUILDPLATFORM python:3.14.2-alpine@sha256:31da4cb527055e4e3d7e9e006dffe9329f84ebea79eaca0a1f1c27ce61e40ca5 AS base
FROM base AS builder
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN apk update \
&& apk add --no-cache g++ linux-headers \
&& rm -rf /var/cache/apk/*
# get packages
COPY requirements.txt .
RUN pip install -r requirements.txt
FROM base
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Enable Profiler
ENV ENABLE_PROFILER=1
RUN apk update \
&& apk add --no-cache libstdc++ \
&& rm -rf /var/cache/apk/*
WORKDIR /email_server
# Grab packages from builder
COPY --from=builder /usr/local/lib/python3.14/ /usr/local/lib/python3.14/
# Add the application
COPY . .
EXPOSE 8080
ENTRYPOINT [ "python", "email_server.py" ]

121
src/emailservice/demo_pb2.py Executable file

File diff suppressed because one or more lines are too long

822
src/emailservice/demo_pb2_grpc.py Executable file
View File

@@ -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)

View File

@@ -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.')

200
src/emailservice/email_server.py Executable file
View File

@@ -0,0 +1,200 @@
#!/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
# @TODO: Temporarily removed in https://github.com/GoogleCloudPlatform/microservices-demo/pull/3196
# 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
# @TODO: Temporarily removed in https://github.com/GoogleCloudPlatform/microservices-demo/pull/3196
# 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)

21
src/emailservice/genproto.sh Executable file
View File

@@ -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]

41
src/emailservice/logger.py Executable file
View File

@@ -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

View File

@@ -0,0 +1,10 @@
google-api-core==2.28.1
grpcio-health-checking==1.76.0
grpcio==1.76.0
jinja2==3.1.6
python-json-logger==4.0.0
google-cloud-trace==1.17.0
requests==2.32.5
opentelemetry-distro==0.60b1
opentelemetry-instrumentation-grpc==0.60b1
opentelemetry-exporter-otlp-proto-grpc==1.39.1

View File

@@ -0,0 +1,120 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements.in -o requirements.txt
cachetools==5.3.2
# via google-auth
certifi==2024.7.4
# via requests
charset-normalizer==3.3.2
# via requests
google-api-core[grpc]==2.28.1
# via
# -r requirements.in
# google-cloud-trace
google-auth==2.23.4
# via
# google-api-core
# google-cloud-trace
google-cloud-trace==1.17.0
# via -r requirements.in
googleapis-common-protos==1.72.0
# via
# google-api-core
# grpcio-status
# opentelemetry-exporter-otlp-proto-grpc
grpcio==1.76.0
# via
# -r requirements.in
# google-api-core
# google-cloud-trace
# grpcio-health-checking
# grpcio-status
# opentelemetry-exporter-otlp-proto-grpc
grpcio-health-checking==1.76.0
# via -r requirements.in
grpcio-status==1.76.0
# via google-api-core
idna==3.7
# via requests
importlib-metadata==6.8.0
# via opentelemetry-api
jinja2==3.1.6
# via -r requirements.in
markupsafe==2.1.3
# via jinja2
opentelemetry-api==1.39.1
# via
# opentelemetry-distro
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-instrumentation
# opentelemetry-instrumentation-grpc
# opentelemetry-sdk
# opentelemetry-semantic-conventions
opentelemetry-distro==0.60b1
# via -r requirements.in
opentelemetry-exporter-otlp-proto-common==1.39.1
# via opentelemetry-exporter-otlp-proto-grpc
opentelemetry-exporter-otlp-proto-grpc==1.39.1
# via -r requirements.in
opentelemetry-instrumentation==0.60b1
# via
# opentelemetry-distro
# opentelemetry-instrumentation-grpc
opentelemetry-instrumentation-grpc==0.60b1
# via -r requirements.in
opentelemetry-proto==1.39.1
# via
# opentelemetry-exporter-otlp-proto-common
# opentelemetry-exporter-otlp-proto-grpc
opentelemetry-sdk==1.39.1
# via
# opentelemetry-distro
# opentelemetry-exporter-otlp-proto-grpc
opentelemetry-semantic-conventions==0.60b1
# via
# opentelemetry-instrumentation
# opentelemetry-instrumentation-grpc
# opentelemetry-sdk
packaging==25.0
# via opentelemetry-instrumentation
proto-plus==1.27.0
# via
# google-api-core
# google-cloud-trace
protobuf==6.33.2
# via
# google-api-core
# 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
python-json-logger==4.0.0
# via -r requirements.in
requests==2.32.5
# via
# -r requirements.in
# google-api-core
rsa==4.9
# via google-auth
typing-extensions==4.15.0
# via
# grpcio
# opentelemetry-api
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-sdk
# opentelemetry-semantic-conventions
urllib3==2.6.3
# via requests
wrapt==1.16.0
# via
# opentelemetry-instrumentation
# opentelemetry-instrumentation-grpc
zipp==3.19.1
# via importlib-metadata

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<!--
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.
-->
<html>
<head>
<title>Your Order Confirmation</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
</head>
<style>
body{
font-family: 'DM Sans', sans-serif;
}
</style>
<body>
<h2>Your Order Confirmation</h2>
<p>Thanks for shopping with us!<p>
<h3>Order ID</h3>
<p>#{{ order.order_id }}</p>
<h3>Shipping</h3>
<p>#{{ order.shipping_tracking_id }}</p>
<p>{{ order.shipping_cost.units }}. {{ "%02d" | format(order.shipping_cost.nanos // 10000000) }} {{ order.shipping_cost.currency_code }}</p>
<p>{{ 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}}</p>
<h3>Items</h3>
<table style="width:100%">
<tr>
<th>Item No.</th>
<th>Quantity</th>
<th>Price</th>
</tr>
{% for item in order.items %}
<tr>
<td>#{{ item.item.product_id }}</td>
<td>{{ item.item.quantity }}</td>
<td>{{ item.cost.units }}.{{ "%02d" | format(item.cost.nanos // 10000000) }} {{ item.cost.currency_code }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>