Skip to content

Commit 26de245

Browse files
authored
Update protobuf (Azure#528)
1 parent 6b86d29 commit 26de245

File tree

6 files changed

+212
-30
lines changed

6 files changed

+212
-30
lines changed

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ trigger:
55
- master
66

77
variables:
8-
DOTNET_VERSION: '2.2.300'
8+
DOTNET_VERSION: '2.2.401'
99

1010
jobs:
1111
- job: Tests

azure_functions_worker/protos/_src/README.md

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,30 @@ From within the Azure Functions language worker repo:
2626
1. Define remote branch for cleaner git commands
2727
- `git remote add proto-file https://github.com/azure/azure-functions-language-worker-protobuf.git`
2828
- `git fetch proto-file`
29-
2. Merge updates
30-
- `git merge -s subtree proto-file/<version branch> --squash --allow-unrelated-histories`
31-
- You can also merge with an explicit path to subtree: `git merge -X subtree=<path in language worker repo> --squash proto-file/<version branch> --allow-unrelated-histories`
32-
3. Finalize with commit
33-
- `git commit -m "Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Branch: <version branch>. Commit: <latest protobuf commit hash>"`
29+
2. Pull a specific release tag
30+
- `git fetch proto-file refs/tags/<tag-name>`
31+
- Example: `git fetch proto-file refs/tags/v1.1.0-protofile`
32+
3. Merge updates
33+
- Merge with an explicit path to subtree: `git merge -X subtree=<path in language worker repo> --squash <tag-name> --allow-unrelated-histories --strategy-option theirs`
34+
- Example: `git merge -X subtree=src/WebJobs.Script.Grpc/azure-functions-language-worker-protobuf --squash v1.1.0-protofile --allow-unrelated-histories --strategy-option theirs`
35+
4. Finalize with commit
36+
- `git commit -m "Updated subtree from https://github.com/azure/azure-functions-language-worker-protobuf. Tag: <tag-name>. Commit: <commit hash>"`
3437
- `git push`
35-
38+
39+
## Releasing a Language Worker Protobuf version
40+
41+
1. Draft a release in the GitHub UI
42+
- Be sure to inculde details of the release
43+
2. Create a release version, following semantic versioning guidelines ([semver.org](https://semver.org/))
44+
3. Tag the version with the pattern: `v<M>.<m>.<p>-protofile` (example: `v1.1.0-protofile`)
45+
3. Merge `dev` to `master`
46+
3647
## Consuming FunctionRPC.proto
3748
*Note: Update versionNumber before running following commands*
3849

3950
## CSharp
4051
```
41-
set NUGET_PATH=%UserProfile%\.nuget\packages
52+
set NUGET_PATH="%UserProfile%\.nuget\packages"
4253
set GRPC_TOOLS_PATH=%NUGET_PATH%\grpc.tools\<versionNumber>\tools\windows_x86
4354
set PROTO_PATH=.\azure-functions-language-worker-protobuf\src\proto
4455
set PROTO=.\azure-functions-language-worker-protobuf\src\proto\FunctionRpc.proto

azure_functions_worker/protos/_src/src/proto/FunctionRpc.proto

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ option go_package ="github.com/Azure/azure-functions-go-worker/internal/rpc";
1010
package AzureFunctionsRpcMessages;
1111

1212
import "google/protobuf/duration.proto";
13+
import "identity/ClaimsIdentityRpc.proto";
14+
import "shared/NullableTypes.proto";
1315

1416
// Interface exported by the server.
1517
service FunctionRpc {
@@ -201,6 +203,9 @@ message FunctionLoadRequest {
201203

202204
// Metadata for the request
203205
RpcFunctionMetadata metadata = 2;
206+
207+
// A flag indicating if managed dependency is enabled or not
208+
bool managed_dependency_enabled = 3;
204209
}
205210

206211
// Worker tells host result of reload
@@ -211,6 +216,9 @@ message FunctionLoadResponse {
211216
// Result of load operation
212217
StatusResult result = 2;
213218
// TODO: return type expected?
219+
220+
// Result of load operation
221+
bool is_dependency_downloaded = 3;
214222
}
215223

216224
// Information on how a Function should be loaded and its bindings
@@ -229,6 +237,9 @@ message RpcFunctionMetadata {
229237

230238
// Bindings info
231239
map<string, BindingInfo> bindings = 6;
240+
241+
// Is set to true for proxy
242+
bool is_proxy = 7;
232243
}
233244

234245
// Host requests worker to invoke a Function
@@ -278,11 +289,35 @@ message TypedData {
278289
bytes bytes = 3;
279290
bytes stream = 4;
280291
RpcHttp http = 5;
281-
sint64 int = 6;
292+
sint64 int = 6;
282293
double double = 7;
294+
CollectionBytes collection_bytes = 8;
295+
CollectionString collection_string = 9;
296+
CollectionDouble collection_double = 10;
297+
CollectionSInt64 collection_sint64 = 11;
283298
}
284299
}
285300

301+
// Used to encapsulate collection string
302+
message CollectionString {
303+
repeated string string = 1;
304+
}
305+
306+
// Used to encapsulate collection bytes
307+
message CollectionBytes {
308+
repeated bytes bytes = 1;
309+
}
310+
311+
// Used to encapsulate collection double
312+
message CollectionDouble {
313+
repeated double double = 1;
314+
}
315+
316+
// Used to encapsulate collection sint64
317+
message CollectionSInt64 {
318+
repeated sint64 sint64 = 1;
319+
}
320+
286321
// Used to describe a given binding on invocation
287322
message ParameterBinding {
288323
// Name for the binding
@@ -368,6 +403,44 @@ message RpcException {
368403
string message = 2;
369404
}
370405

406+
// Http cookie type. Note that only name and value are used for Http requests
407+
message RpcHttpCookie {
408+
// Enum that lets servers require that a cookie shouoldn't be sent with cross-site requests
409+
enum SameSite {
410+
None = 0;
411+
Lax = 1;
412+
Strict = 2;
413+
}
414+
415+
// Cookie name
416+
string name = 1;
417+
418+
// Cookie value
419+
string value = 2;
420+
421+
// Specifies allowed hosts to receive the cookie
422+
NullableString domain = 3;
423+
424+
// Specifies URL path that must exist in the requested URL
425+
NullableString path = 4;
426+
427+
// Sets the cookie to expire at a specific date instead of when the client closes.
428+
// It is generally recommended that you use "Max-Age" over "Expires".
429+
NullableTimestamp expires = 5;
430+
431+
// Sets the cookie to only be sent with an encrypted request
432+
NullableBool secure = 6;
433+
434+
// Sets the cookie to be inaccessible to JavaScript's Document.cookie API
435+
NullableBool http_only = 7;
436+
437+
// Allows servers to assert that a cookie ought not to be sent along with cross-site requests
438+
SameSite same_site = 8;
439+
440+
// Number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately.
441+
NullableDouble max_age = 9;
442+
}
443+
371444
// TODO - solidify this or remove it
372445
message RpcHttp {
373446
string method = 1;
@@ -379,4 +452,6 @@ message RpcHttp {
379452
map<string,string> query = 15;
380453
bool enable_content_negotiation= 16;
381454
TypedData rawBody = 17;
455+
repeated RpcClaimsIdentity identities = 18;
456+
repeated RpcHttpCookie cookies = 19;
382457
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
syntax = "proto3";
2+
// protobuf vscode extension: https://marketplace.visualstudio.com/items?itemName=zxh404.vscode-proto3
3+
4+
option java_package = "com.microsoft.azure.functions.rpc.messages";
5+
6+
import "shared/NullableTypes.proto";
7+
8+
// Light-weight representation of a .NET System.Security.Claims.ClaimsIdentity object.
9+
// This is the same serialization as found in EasyAuth, and needs to be kept in sync with
10+
// its ClaimsIdentitySlim definition, as seen in the WebJobs extension:
11+
// https://github.com/Azure/azure-webjobs-sdk-extensions/blob/dev/src/WebJobs.Extensions.Http/ClaimsIdentitySlim.cs
12+
message RpcClaimsIdentity {
13+
NullableString authentication_type = 1;
14+
NullableString name_claim_type = 2;
15+
NullableString role_claim_type = 3;
16+
repeated RpcClaim claims = 4;
17+
}
18+
19+
// Light-weight representation of a .NET System.Security.Claims.Claim object.
20+
// This is the same serialization as found in EasyAuth, and needs to be kept in sync with
21+
// its ClaimSlim definition, as seen in the WebJobs extension:
22+
// https://github.com/Azure/azure-webjobs-sdk-extensions/blob/dev/src/WebJobs.Extensions.Http/ClaimSlim.cs
23+
message RpcClaim {
24+
string value = 1;
25+
string type = 2;
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
syntax = "proto3";
2+
// protobuf vscode extension: https://marketplace.visualstudio.com/items?itemName=zxh404.vscode-proto3
3+
4+
option java_package = "com.microsoft.azure.functions.rpc.messages";
5+
6+
import "google/protobuf/timestamp.proto";
7+
8+
message NullableString {
9+
oneof string {
10+
string value = 1;
11+
}
12+
}
13+
14+
message NullableDouble {
15+
oneof double {
16+
double value = 1;
17+
}
18+
}
19+
20+
message NullableBool {
21+
oneof bool {
22+
bool value = 1;
23+
}
24+
}
25+
26+
message NullableTimestamp {
27+
oneof timestamp {
28+
google.protobuf.Timestamp value = 1;
29+
}
30+
}

setup.py

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@
88
import tempfile
99
import urllib.request
1010
import zipfile
11+
import re
12+
from distutils import dir_util
1113
from distutils.command import build
1214

1315
from setuptools import setup
1416
from setuptools.command import develop
1517

1618

1719
# TODO: change this to something more stable when available.
18-
WEBHOST_URL = ('https://ci.appveyor.com/api/buildjobs/1em48j4cd3odl4s9'
20+
WEBHOST_URL = ('https://ci.appveyor.com/api/buildjobs/sfelyng3x6p5sus0'
1921
'/artifacts'
20-
'/Functions.Binaries.2.0.12521-prerelease.no-runtime.zip')
22+
'/Functions.Binaries.2.0.12642.no-runtime.zip')
2123

2224
# Extensions necessary for non-core bindings.
2325
AZURE_EXTENSIONS = [
@@ -73,36 +75,74 @@ def _gen_grpc(self):
7375

7476
proto_root_dir = root / 'azure_functions_worker' / 'protos'
7577
proto_src_dir = proto_root_dir / '_src' / 'src' / 'proto'
76-
staging_root_dir = root / 'build' / 'protos'
78+
build_dir = root / 'build'
79+
staging_root_dir = build_dir / 'protos'
7780
staging_dir = (staging_root_dir
7881
/ 'azure_functions_worker' / 'protos')
79-
build_dir = staging_dir / 'azure_functions_worker' / 'protos'
82+
built_protos_dir = build_dir / 'built_protos'
8083

81-
if os.path.exists(build_dir):
82-
shutil.rmtree(build_dir)
84+
if os.path.exists(staging_root_dir):
85+
shutil.rmtree(staging_root_dir)
8386

84-
shutil.copytree(proto_src_dir, build_dir)
87+
if os.path.exists(built_protos_dir):
88+
shutil.rmtree(built_protos_dir)
8589

86-
subprocess.run([
87-
sys.executable, '-m', 'grpc_tools.protoc',
88-
'-I', os.sep.join(('azure_functions_worker', 'protos')),
89-
'--python_out', str(staging_root_dir),
90-
'--grpc_python_out', str(staging_root_dir),
91-
os.sep.join(('azure_functions_worker', 'protos',
92-
'azure_functions_worker', 'protos',
93-
'FunctionRpc.proto')),
94-
], check=True, stdout=sys.stdout, stderr=sys.stderr,
95-
cwd=staging_root_dir)
90+
shutil.copytree(proto_src_dir, staging_dir)
9691

97-
compiled = glob.glob(str(staging_dir / '*.py'))
92+
os.makedirs(built_protos_dir)
9893

99-
if not compiled:
94+
protos = [
95+
os.sep.join(('shared', 'NullableTypes.proto')),
96+
os.sep.join(('identity', 'ClaimsIdentityRpc.proto')),
97+
'FunctionRpc.proto'
98+
]
99+
100+
for proto in protos:
101+
subprocess.run([
102+
sys.executable, '-m', 'grpc_tools.protoc',
103+
'-I', os.sep.join(('azure_functions_worker', 'protos')),
104+
'--python_out', str(built_protos_dir),
105+
'--grpc_python_out', str(built_protos_dir),
106+
os.sep.join(('azure_functions_worker', 'protos', proto)),
107+
], check=True, stdout=sys.stdout, stderr=sys.stderr,
108+
cwd=staging_root_dir)
109+
110+
compiled_files = glob.glob(
111+
str(built_protos_dir / '**' / '*.py'),
112+
recursive=True)
113+
114+
if not compiled_files:
100115
print('grpc_tools.protoc produced no Python files',
101116
file=sys.stderr)
102117
sys.exit(1)
103118

104-
for f in compiled:
105-
shutil.copy(f, proto_root_dir)
119+
# Needed to support absolute imports in files. See
120+
# https://github.com/protocolbuffers/protobuf/issues/1491
121+
self.make_absolute_imports(compiled_files)
122+
123+
dir_util.copy_tree(built_protos_dir, str(proto_root_dir))
124+
125+
def make_absolute_imports(self, compiled_files):
126+
for compiled in compiled_files:
127+
with open(compiled, 'r+') as f:
128+
content = f.read()
129+
f.seek(0)
130+
# Convert lines of the form:
131+
# import xxx_pb2 as xxx__pb2 to
132+
# from azure_functions_worker.protos import xxx_pb2 as..
133+
p1 = re.sub(
134+
r'\nimport (.*?_pb2)',
135+
r'\nfrom azure_functions_worker.protos import \g<1>',
136+
content)
137+
# Convert lines of the form:
138+
# from identity import xxx_pb2 as.. to
139+
# from azure_functions_worker.protos.identity import xxx_pb2..
140+
p2 = re.sub(
141+
r'from ([a-z]*) (import.*_pb2)',
142+
r'from azure_functions_worker.protos.\g<1> \g<2>',
143+
p1)
144+
f.write(p2)
145+
f.truncate()
106146

107147

108148
class build(build.build, BuildGRPC):

0 commit comments

Comments
 (0)