Merge branch 'master' into epoll1_h2proxy_tests_fix

pull/12750/head
Yash Tibrewal 7 years ago
commit 39f0895c02
  1. 1
      doc/environment_variables.md
  2. 2
      include/grpc/grpc.h
  3. 35
      include/grpc/grpc_security.h
  4. 4
      include/grpc/impl/codegen/port_platform.h
  5. 4
      setup.py
  6. 4
      src/core/lib/iomgr/socket_utils_windows.c
  7. 134
      src/core/lib/iomgr/timer_generic.c
  8. 3
      src/core/lib/iomgr/timer_generic.h
  9. 14
      src/core/lib/security/credentials/composite/composite_credentials.c
  10. 182
      src/core/lib/security/credentials/plugin/plugin_credentials.c
  11. 2
      src/core/lib/security/credentials/plugin/plugin_credentials.h
  12. 6
      src/core/lib/surface/init_secure.c
  13. 80
      src/cpp/client/secure_credentials.cc
  14. 17
      src/cpp/client/secure_credentials.h
  15. 9
      src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
  16. 59
      src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
  17. 8
      src/csharp/ext/grpc_csharp_ext.c
  18. 10
      src/node/ext/call_credentials.cc
  19. 8
      src/node/ext/call_credentials.h
  20. 46
      src/php/ext/grpc/call_credentials.c
  21. 9
      src/php/ext/grpc/call_credentials.h
  22. 10
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
  23. 45
      src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
  24. 11
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  25. 14
      src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
  26. 2
      src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py
  27. 8
      src/ruby/ext/grpc/rb_call_credentials.c
  28. 4
      templates/test/cpp/naming/create_private_dns_zone.sh.template
  29. 32
      templates/test/cpp/naming/create_private_dns_zone_defs.include
  30. 4
      templates/test/cpp/naming/private_dns_zone_init.sh.template
  31. 40
      templates/test/cpp/naming/private_dns_zone_init_defs.include
  32. 64
      templates/test/cpp/naming/resolver_gce_integration_tests_defs.include
  33. 4
      templates/test/cpp/naming/resolver_gce_integration_tests_runner.sh.template
  34. 2
      templates/tools/dockerfile/python_deps.include
  35. 43
      test/core/security/credentials_test.c
  36. 28
      test/cpp/end2end/end2end_test.cc
  37. 43
      test/cpp/naming/README.md
  38. 27
      test/cpp/naming/create_private_dns_zone.sh
  39. 110
      test/cpp/naming/gen_build_yaml.py
  40. 215
      test/cpp/naming/private_dns_zone_init.sh
  41. 26
      test/cpp/naming/resolver_component_tests_runner.sh
  42. 359
      test/cpp/naming/resolver_gce_integration_tests_runner.sh
  43. 2
      test/cpp/naming/resolver_test_record_groups.yaml
  44. 2
      test/cpp/naming/test_dns_server.py
  45. 80
      tools/distrib/pull_requests_interval.sh
  46. 2
      tools/distrib/pylint_code.sh
  47. 2
      tools/distrib/python/docgen.py
  48. 2
      tools/distrib/yapf_code.sh
  49. 2
      tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
  50. 2
      tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
  51. 2
      tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
  52. 2
      tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
  53. 2
      tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
  54. 2
      tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
  55. 2
      tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
  56. 2
      tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
  57. 2
      tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
  58. 2
      tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
  59. 2
      tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
  60. 2
      tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
  61. 2
      tools/dockerfile/test/csharp_jessie_x64/Dockerfile
  62. 2
      tools/dockerfile/test/cxx_alpine_x64/Dockerfile
  63. 2
      tools/dockerfile/test/cxx_jessie_x64/Dockerfile
  64. 2
      tools/dockerfile/test/cxx_jessie_x86/Dockerfile
  65. 2
      tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
  66. 2
      tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
  67. 2
      tools/dockerfile/test/fuzzer/Dockerfile
  68. 2
      tools/dockerfile/test/multilang_jessie_x64/Dockerfile
  69. 2
      tools/dockerfile/test/node_jessie_x64/Dockerfile
  70. 2
      tools/dockerfile/test/php7_jessie_x64/Dockerfile
  71. 2
      tools/dockerfile/test/php_jessie_x64/Dockerfile
  72. 2
      tools/dockerfile/test/python_alpine_x64/Dockerfile
  73. 2
      tools/dockerfile/test/python_jessie_x64/Dockerfile
  74. 2
      tools/dockerfile/test/python_pyenv_x64/Dockerfile
  75. 2
      tools/dockerfile/test/ruby_jessie_x64/Dockerfile
  76. 2
      tools/dockerfile/test/sanity/Dockerfile
  77. 1
      tools/gce/linux_performance_worker_init.sh
  78. 2
      tools/internal_ci/linux/grpc_performance_profile_daily.sh
  79. 16
      tools/interop_matrix/README.md
  80. 2
      tools/jenkins/run_performance_profile_daily.sh
  81. 16
      tools/profiling/microbenchmarks/bm_diff/bm_main.py
  82. 9
      tools/profiling/microbenchmarks/bm_diff/bm_run.py
  83. 2
      tools/run_tests/helper_scripts/build_python.sh
  84. 28
      tools/run_tests/helper_scripts/run_grpc-node.sh
  85. 2
      tools/run_tests/python_utils/filter_pull_request_tests.py
  86. 62
      tools/run_tests/run_tests.py
  87. 2
      tools/run_tests/run_tests_matrix.py
  88. 2
      tools/run_tests/sanity/check_test_filtering.py

@ -58,6 +58,7 @@ some configuration as environment variables that can be set.
completion queue
- round_robin - traces the round_robin load balancing policy
- pick_first - traces the pick first load balancing policy
- plugin_credentials - traces plugin credentials
- resource_quota - trace resource quota objects internals
- glb - traces the grpclb load balancer
- queue_pluck

@ -313,7 +313,7 @@ GRPCAPI grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
void *reserved);
/** Ref a call.
THREAD SAFETY: grpc_call_unref is thread-compatible */
THREAD SAFETY: grpc_call_ref is thread-compatible */
GRPCAPI void grpc_call_ref(grpc_call *call);
/** Unref a call.

@ -249,19 +249,40 @@ typedef struct {
void *reserved;
} grpc_auth_metadata_context;
/** Maximum number of metadata entries returnable by a credentials plugin via
a synchronous return. */
#define GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX 4
/** grpc_metadata_credentials plugin is an API user provided structure used to
create grpc_credentials objects that can be set on a channel (composed) or
a call. See grpc_credentials_metadata_create_from_plugin below.
The grpc client stack will call the get_metadata method of the plugin for
every call in scope for the credentials created from it. */
typedef struct {
/** The implementation of this method has to be non-blocking.
- context is the information that can be used by the plugin to create auth
metadata.
- cb is the callback that needs to be called when the metadata is ready.
- user_data needs to be passed as the first parameter of the callback. */
void (*get_metadata)(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data);
/** The implementation of this method has to be non-blocking, but can
be performed synchronously or asynchronously.
If processing occurs synchronously, returns non-zero and populates
creds_md, num_creds_md, status, and error_details. In this case,
the caller takes ownership of the entries in creds_md and of
error_details. Note that if the plugin needs to return more than
GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX entries in creds_md, it must
return asynchronously.
If processing occurs asynchronously, returns zero and invokes \a cb
when processing is completed. \a user_data will be passed as the
first parameter of the callback. NOTE: \a cb MUST be invoked in a
different thread, not from the thread in which \a get_metadata() is
invoked.
\a context is the information that can be used by the plugin to create
auth metadata. */
int (*get_metadata)(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details);
/** Destroys the plugin state. */
void (*destroy)(void *state);

@ -291,10 +291,6 @@
#endif
#ifdef _MSC_VER
#ifdef _PYTHON_MSVC
// The Python 3.5 Windows runtime is missing InetNtop
#define GPR_WIN_INET_NTOP
#endif // _PYTHON_MSVC
#if _MSC_VER < 1700
typedef __int8 int8_t;
typedef __int16 int16_t;

@ -110,8 +110,6 @@ if EXTRA_ENV_COMPILE_ARGS is None:
EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime32 -D_timeb=__timeb32 -D_ftime_s=_ftime32_s'
else:
EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime64 -D_timeb=__timeb64'
elif 'win32' in sys.platform:
EXTRA_ENV_COMPILE_ARGS += ' -D_PYTHON_MSVC'
elif "linux" in sys.platform:
EXTRA_ENV_COMPILE_ARGS += ' -std=c++11 -std=gnu99 -fvisibility=hidden -fno-wrapv -fno-exceptions'
elif "darwin" in sys.platform:
@ -163,7 +161,7 @@ if "win32" in sys.platform:
# TODO(zyc): Re-enble c-ares on x64 and x86 windows after fixing the
# ares_library_init compilation issue
DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1), ('CARES_STATICLIB', 1),
('GRPC_ARES', 0),)
('GRPC_ARES', 0), ('NTDDI_VERSION', 0x06000000),)
if '64bit' in platform.architecture()[0]:
DEFINE_MACROS += (('MS_WIN64', 1),)
elif sys.version_info >= (3, 5):

@ -26,12 +26,8 @@
#include <grpc/support/log.h>
const char *grpc_inet_ntop(int af, const void *src, char *dst, size_t size) {
#ifdef GPR_WIN_INET_NTOP
return inet_ntop(af, src, dst, size);
#else
/* Windows InetNtopA wants a mutable ip pointer */
return InetNtopA(af, (void *)src, dst, size);
#endif /* GPR_WIN_INET_NTOP */
}
#endif /* GRPC_WINDOWS_SOCKETUTILS */

@ -79,6 +79,125 @@ static timer_shard g_shards[NUM_SHARDS];
* Access to this is protected by g_shared_mutables.mu */
static timer_shard *g_shard_queue[NUM_SHARDS];
#ifndef NDEBUG
/* == Hash table for duplicate timer detection == */
#define NUM_HASH_BUCKETS 1009 /* Prime number close to 1000 */
static gpr_mu g_hash_mu[NUM_HASH_BUCKETS]; /* One mutex per bucket */
static grpc_timer *g_timer_ht[NUM_HASH_BUCKETS] = {NULL};
static void init_timer_ht() {
for (int i = 0; i < NUM_HASH_BUCKETS; i++) {
gpr_mu_init(&g_hash_mu[i]);
}
}
static bool is_in_ht(grpc_timer *t) {
size_t i = GPR_HASH_POINTER(t, NUM_HASH_BUCKETS);
gpr_mu_lock(&g_hash_mu[i]);
grpc_timer *p = g_timer_ht[i];
while (p != NULL && p != t) {
p = p->hash_table_next;
}
gpr_mu_unlock(&g_hash_mu[i]);
return (p == t);
}
static void add_to_ht(grpc_timer *t) {
GPR_ASSERT(!t->hash_table_next);
size_t i = GPR_HASH_POINTER(t, NUM_HASH_BUCKETS);
gpr_mu_lock(&g_hash_mu[i]);
grpc_timer *p = g_timer_ht[i];
while (p != NULL && p != t) {
p = p->hash_table_next;
}
if (p == t) {
grpc_closure *c = t->closure;
gpr_log(GPR_ERROR,
"** Duplicate timer (%p) being added. Closure: (%p), created at: "
"(%s:%d), scheduled at: (%s:%d) **",
t, c, c->file_created, c->line_created, c->file_initiated,
c->line_initiated);
abort();
}
/* Timer not present in the bucket. Insert at head of the list */
t->hash_table_next = g_timer_ht[i];
g_timer_ht[i] = t;
gpr_mu_unlock(&g_hash_mu[i]);
}
static void remove_from_ht(grpc_timer *t) {
size_t i = GPR_HASH_POINTER(t, NUM_HASH_BUCKETS);
bool removed = false;
gpr_mu_lock(&g_hash_mu[i]);
if (g_timer_ht[i] == t) {
g_timer_ht[i] = g_timer_ht[i]->hash_table_next;
removed = true;
} else if (g_timer_ht[i] != NULL) {
grpc_timer *p = g_timer_ht[i];
while (p->hash_table_next != NULL && p->hash_table_next != t) {
p = p->hash_table_next;
}
if (p->hash_table_next == t) {
p->hash_table_next = t->hash_table_next;
removed = true;
}
}
gpr_mu_unlock(&g_hash_mu[i]);
if (!removed) {
grpc_closure *c = t->closure;
gpr_log(GPR_ERROR,
"** Removing timer (%p) that is not added to hash table. Closure "
"(%p), created at: (%s:%d), scheduled at: (%s:%d) **",
t, c, c->file_created, c->line_created, c->file_initiated,
c->line_initiated);
abort();
}
t->hash_table_next = NULL;
}
/* If a timer is added to a timer shard (either heap or a list), it cannot
* be pending. A timer is added to hash table only-if it is added to the
* timer shard.
* Therefore, if timer->pending is false, it cannot be in hash table */
static void validate_non_pending_timer(grpc_timer *t) {
if (!t->pending && is_in_ht(t)) {
grpc_closure *c = t->closure;
gpr_log(GPR_ERROR,
"** gpr_timer_cancel() called on a non-pending timer (%p) which "
"is in the hash table. Closure: (%p), created at: (%s:%d), "
"scheduled at: (%s:%d) **",
t, c, c->file_created, c->line_created, c->file_initiated,
c->line_initiated);
abort();
}
}
#define INIT_TIMER_HASH_TABLE() init_timer_ht()
#define ADD_TO_HASH_TABLE(t) add_to_ht((t))
#define REMOVE_FROM_HASH_TABLE(t) remove_from_ht((t))
#define VALIDATE_NON_PENDING_TIMER(t) validate_non_pending_timer((t))
#else
#define INIT_TIMER_HASH_TABLE()
#define ADD_TO_HASH_TABLE(t)
#define REMOVE_FROM_HASH_TABLE(t)
#define VALIDATE_NON_PENDING_TIMER(t)
#endif
/* Thread local variable that stores the deadline of the next timer the thread
* has last-seen. This is an optimization to prevent the thread from checking
* shared_mutables.min_timer (which requires acquiring shared_mutables.mu lock,
@ -175,6 +294,8 @@ void grpc_timer_list_init(gpr_timespec now) {
shard->min_deadline = compute_min_deadline(shard);
g_shard_queue[i] = shard;
}
INIT_TIMER_HASH_TABLE();
}
void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {
@ -245,6 +366,10 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
timer->closure = closure;
gpr_atm deadline_atm = timer->deadline = timespec_to_atm_round_up(deadline);
#ifndef NDEBUG
timer->hash_table_next = NULL;
#endif
if (GRPC_TRACER_ON(grpc_timer_trace)) {
gpr_log(GPR_DEBUG, "TIMER %p: SET %" PRId64 ".%09d [%" PRIdPTR
"] now %" PRId64 ".%09d [%" PRIdPTR "] call %p[%p]",
@ -272,6 +397,9 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
grpc_time_averaged_stats_add_sample(&shard->stats,
ts_to_dbl(gpr_time_sub(deadline, now)));
ADD_TO_HASH_TABLE(timer);
if (deadline_atm < shard->queue_deadline_cap) {
is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
} else {
@ -333,7 +461,10 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
gpr_log(GPR_DEBUG, "TIMER %p: CANCEL pending=%s", timer,
timer->pending ? "true" : "false");
}
if (timer->pending) {
REMOVE_FROM_HASH_TABLE(timer);
GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
timer->pending = false;
if (timer->heap_index == INVALID_HEAP_INDEX) {
@ -341,6 +472,8 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
} else {
grpc_timer_heap_remove(&shard->heap, timer);
}
} else {
VALIDATE_NON_PENDING_TIMER(timer);
}
gpr_mu_unlock(&shard->mu);
}
@ -424,6 +557,7 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, timer_shard *shard,
grpc_timer *timer;
gpr_mu_lock(&shard->mu);
while ((timer = pop_one(shard, now))) {
REMOVE_FROM_HASH_TABLE(timer);
GRPC_CLOSURE_SCHED(exec_ctx, timer->closure, GRPC_ERROR_REF(error));
n++;
}

@ -29,6 +29,9 @@ struct grpc_timer {
struct grpc_timer *next;
struct grpc_timer *prev;
grpc_closure *closure;
#ifndef NDEBUG
struct grpc_timer *hash_table_next;
#endif
};
#endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */

@ -87,6 +87,7 @@ static bool composite_call_get_request_metadata(
ctx->on_request_metadata = on_request_metadata;
GRPC_CLOSURE_INIT(&ctx->internal_on_request_metadata,
composite_call_metadata_cb, ctx, grpc_schedule_on_exec_ctx);
bool synchronous = true;
while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
grpc_call_credentials *inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
@ -95,19 +96,12 @@ static bool composite_call_get_request_metadata(
ctx->md_array, &ctx->internal_on_request_metadata, error)) {
if (*error != GRPC_ERROR_NONE) break;
} else {
synchronous = false; // Async return.
break;
}
}
// If we got through all creds synchronously or we got a synchronous
// error on one of them, return synchronously.
if (ctx->creds_index == ctx->composite_creds->inner.num_creds ||
*error != GRPC_ERROR_NONE) {
gpr_free(ctx);
return true;
}
// At least one inner cred is returning asynchronously, so we'll
// return asynchronously as well.
return false;
if (synchronous) gpr_free(ctx);
return synchronous;
}
static void composite_call_cancel_get_request_metadata(

@ -31,6 +31,9 @@
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/validate_metadata.h"
grpc_tracer_flag grpc_plugin_credentials_trace =
GRPC_TRACER_INITIALIZER(false, "plugin_credentials");
static void plugin_destruct(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds) {
grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
@ -53,6 +56,62 @@ static void pending_request_remove_locked(
}
}
// Checks if the request has been cancelled.
// If not, removes it from the pending list, so that it cannot be
// cancelled out from under us.
// When this returns, r->cancelled indicates whether the request was
// cancelled before completion.
static void pending_request_complete(
grpc_exec_ctx *exec_ctx, grpc_plugin_credentials_pending_request *r) {
gpr_mu_lock(&r->creds->mu);
if (!r->cancelled) pending_request_remove_locked(r->creds, r);
gpr_mu_unlock(&r->creds->mu);
// Ref to credentials not needed anymore.
grpc_call_credentials_unref(exec_ctx, &r->creds->base);
}
static grpc_error *process_plugin_result(
grpc_exec_ctx *exec_ctx, grpc_plugin_credentials_pending_request *r,
const grpc_metadata *md, size_t num_md, grpc_status_code status,
const char *error_details) {
grpc_error *error = GRPC_ERROR_NONE;
if (status != GRPC_STATUS_OK) {
char *msg;
gpr_asprintf(&msg, "Getting metadata from plugin failed with error: %s",
error_details);
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
} else {
bool seen_illegal_header = false;
for (size_t i = 0; i < num_md; ++i) {
if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin",
grpc_validate_header_key_is_legal(md[i].key))) {
seen_illegal_header = true;
break;
} else if (!grpc_is_binary_header(md[i].key) &&
!GRPC_LOG_IF_ERROR(
"validate_metadata_from_plugin",
grpc_validate_header_nonbin_value_is_legal(md[i].value))) {
gpr_log(GPR_ERROR, "Plugin added invalid metadata value.");
seen_illegal_header = true;
break;
}
}
if (seen_illegal_header) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal metadata");
} else {
for (size_t i = 0; i < num_md; ++i) {
grpc_mdelem mdelem = grpc_mdelem_from_slices(
exec_ctx, grpc_slice_ref_internal(md[i].key),
grpc_slice_ref_internal(md[i].value));
grpc_credentials_mdelem_array_add(r->md_array, mdelem);
GRPC_MDELEM_UNREF(exec_ctx, mdelem);
}
}
}
return error;
}
static void plugin_md_request_metadata_ready(void *request,
const grpc_metadata *md,
size_t num_md,
@ -64,54 +123,24 @@ static void plugin_md_request_metadata_ready(void *request,
NULL, NULL);
grpc_plugin_credentials_pending_request *r =
(grpc_plugin_credentials_pending_request *)request;
// Check if the request has been cancelled.
// If not, remove it from the pending list, so that it cannot be
// cancelled out from under us.
gpr_mu_lock(&r->creds->mu);
if (!r->cancelled) pending_request_remove_locked(r->creds, r);
gpr_mu_unlock(&r->creds->mu);
grpc_call_credentials_unref(&exec_ctx, &r->creds->base);
if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
"asynchronously",
r->creds, r);
}
// Remove request from pending list if not previously cancelled.
pending_request_complete(&exec_ctx, r);
// If it has not been cancelled, process it.
if (!r->cancelled) {
if (status != GRPC_STATUS_OK) {
char *msg;
gpr_asprintf(&msg, "Getting metadata from plugin failed with error: %s",
error_details);
GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata,
GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
} else {
bool seen_illegal_header = false;
for (size_t i = 0; i < num_md; ++i) {
if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin",
grpc_validate_header_key_is_legal(md[i].key))) {
seen_illegal_header = true;
break;
} else if (!grpc_is_binary_header(md[i].key) &&
!GRPC_LOG_IF_ERROR(
"validate_metadata_from_plugin",
grpc_validate_header_nonbin_value_is_legal(
md[i].value))) {
gpr_log(GPR_ERROR, "Plugin added invalid metadata value.");
seen_illegal_header = true;
break;
}
}
if (seen_illegal_header) {
GRPC_CLOSURE_SCHED(
&exec_ctx, r->on_request_metadata,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal metadata"));
} else {
for (size_t i = 0; i < num_md; ++i) {
grpc_mdelem mdelem = grpc_mdelem_from_slices(
&exec_ctx, grpc_slice_ref_internal(md[i].key),
grpc_slice_ref_internal(md[i].value));
grpc_credentials_mdelem_array_add(r->md_array, mdelem);
GRPC_MDELEM_UNREF(&exec_ctx, mdelem);
}
GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, GRPC_ERROR_NONE);
}
}
grpc_error *error =
process_plugin_result(&exec_ctx, r, md, num_md, status, error_details);
GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, error);
} else if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin was previously "
"cancelled",
r->creds, r);
}
gpr_free(r);
grpc_exec_ctx_finish(&exec_ctx);
@ -125,6 +154,7 @@ static bool plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_closure *on_request_metadata,
grpc_error **error) {
grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
bool retval = true; // Synchronous return.
if (c->plugin.get_metadata != NULL) {
// Create pending_request object.
grpc_plugin_credentials_pending_request *pending_request =
@ -142,12 +172,60 @@ static bool plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
c->pending_requests = pending_request;
gpr_mu_unlock(&c->mu);
// Invoke the plugin. The callback holds a ref to us.
if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin",
c, pending_request);
}
grpc_call_credentials_ref(creds);
c->plugin.get_metadata(c->plugin.state, context,
plugin_md_request_metadata_ready, pending_request);
return false;
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX];
size_t num_creds_md = 0;
grpc_status_code status = GRPC_STATUS_OK;
const char *error_details = NULL;
if (!c->plugin.get_metadata(c->plugin.state, context,
plugin_md_request_metadata_ready,
pending_request, creds_md, &num_creds_md,
&status, &error_details)) {
if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin will return "
"asynchronously",
c, pending_request);
}
return false; // Asynchronous return.
}
// Returned synchronously.
// Remove request from pending list if not previously cancelled.
pending_request_complete(exec_ctx, pending_request);
// If the request was cancelled, the error will have been returned
// asynchronously by plugin_cancel_get_request_metadata(), so return
// false. Otherwise, process the result.
if (pending_request->cancelled) {
if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p was cancelled, error "
"will be returned asynchronously",
c, pending_request);
}
retval = false;
} else {
if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
"synchronously",
c, pending_request);
}
*error = process_plugin_result(exec_ctx, pending_request, creds_md,
num_creds_md, status, error_details);
}
// Clean up.
for (size_t i = 0; i < num_creds_md; ++i) {
grpc_slice_unref_internal(exec_ctx, creds_md[i].key);
grpc_slice_unref_internal(exec_ctx, creds_md[i].value);
}
gpr_free((void *)error_details);
gpr_free(pending_request);
}
return true;
return retval;
}
static void plugin_cancel_get_request_metadata(
@ -159,6 +237,10 @@ static void plugin_cancel_get_request_metadata(
c->pending_requests;
pending_request != NULL; pending_request = pending_request->next) {
if (pending_request->md_array == md_array) {
if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", c,
pending_request);
}
pending_request->cancelled = true;
GRPC_CLOSURE_SCHED(exec_ctx, pending_request->on_request_metadata,
GRPC_ERROR_REF(error));

@ -21,6 +21,8 @@
#include "src/core/lib/security/credentials/credentials.h"
extern grpc_tracer_flag grpc_plugin_credentials_trace;
struct grpc_plugin_credentials;
typedef struct grpc_plugin_credentials_pending_request {

@ -25,6 +25,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/plugin/plugin_credentials.h"
#include "src/core/lib/security/transport/auth_filters.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_connector.h"
@ -84,4 +85,7 @@ void grpc_register_security_filters(void) {
maybe_prepend_server_auth_filter, NULL);
}
void grpc_security_init() { grpc_security_register_handshaker_factories(); }
void grpc_security_init() {
grpc_security_register_handshaker_factories();
grpc_register_tracer(&grpc_plugin_credentials_trace);
}

@ -21,6 +21,7 @@
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/channel_arguments.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/cpp/client/create_channel_internal.h"
#include "src/cpp/common/secure_auth_context.h"
@ -150,6 +151,18 @@ std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
return nullptr;
}
std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2) {
SecureCallCredentials* s_creds1 = creds1->AsSecureCredentials();
SecureCallCredentials* s_creds2 = creds2->AsSecureCredentials();
if (s_creds1 != nullptr && s_creds2 != nullptr) {
return WrapCallCredentials(grpc_composite_call_credentials_create(
s_creds1->GetRawCreds(), s_creds2->GetRawCreds(), nullptr));
}
return nullptr;
}
void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
if (wrapper == nullptr) return;
MetadataCredentialsPluginWrapper* w =
@ -157,28 +170,50 @@ void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
delete w;
}
void MetadataCredentialsPluginWrapper::GetMetadata(
int MetadataCredentialsPluginWrapper::GetMetadata(
void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data) {
grpc_credentials_plugin_metadata_cb cb, void* user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t* num_creds_md, grpc_status_code* status,
const char** error_details) {
GPR_ASSERT(wrapper);
MetadataCredentialsPluginWrapper* w =
reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
if (!w->plugin_) {
cb(user_data, NULL, 0, GRPC_STATUS_OK, NULL);
return;
*num_creds_md = 0;
*status = GRPC_STATUS_OK;
*error_details = nullptr;
return true;
}
if (w->plugin_->IsBlocking()) {
// Asynchronous return.
w->thread_pool_->Add(
std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w, context,
cb, user_data));
cb, user_data, nullptr, nullptr, nullptr, nullptr));
return 0;
} else {
w->InvokePlugin(context, cb, user_data);
// Synchronous return.
w->InvokePlugin(context, cb, user_data, creds_md, num_creds_md, status,
error_details);
return 1;
}
}
namespace {
void UnrefMetadata(const std::vector<grpc_metadata>& md) {
for (auto it = md.begin(); it != md.end(); ++it) {
grpc_slice_unref(it->key);
grpc_slice_unref(it->value);
}
}
} // namespace
void MetadataCredentialsPluginWrapper::InvokePlugin(
grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb,
void* user_data) {
void* user_data, grpc_metadata creds_md[4], size_t* num_creds_md,
grpc_status_code* status_code, const char** error_details) {
std::multimap<grpc::string, grpc::string> metadata;
// const_cast is safe since the SecureAuthContext does not take owndership and
@ -196,12 +231,31 @@ void MetadataCredentialsPluginWrapper::InvokePlugin(
md_entry.flags = 0;
md.push_back(md_entry);
}
cb(user_data, md.empty() ? nullptr : &md[0], md.size(),
static_cast<grpc_status_code>(status.error_code()),
status.error_message().c_str());
for (auto it = md.begin(); it != md.end(); ++it) {
grpc_slice_unref(it->key);
grpc_slice_unref(it->value);
if (creds_md != nullptr) {
// Synchronous return.
if (md.size() > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
*num_creds_md = 0;
*status_code = GRPC_STATUS_INTERNAL;
*error_details = gpr_strdup(
"blocking plugin credentials returned too many metadata keys");
UnrefMetadata(md);
} else {
for (const auto& elem : md) {
creds_md[*num_creds_md].key = elem.key;
creds_md[*num_creds_md].value = elem.value;
creds_md[*num_creds_md].flags = elem.flags;
++(*num_creds_md);
}
*status_code = static_cast<grpc_status_code>(status.error_code());
*error_details =
status.ok() ? nullptr : gpr_strdup(status.error_message().c_str());
}
} else {
// Asynchronous return.
cb(user_data, md.empty() ? nullptr : &md[0], md.size(),
static_cast<grpc_status_code>(status.error_code()),
status.error_message().c_str());
UnrefMetadata(md);
}
}

@ -58,16 +58,23 @@ class SecureCallCredentials final : public CallCredentials {
class MetadataCredentialsPluginWrapper final : private GrpcLibraryCodegen {
public:
static void Destroy(void* wrapper);
static void GetMetadata(void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void* user_data);
static int GetMetadata(
void* wrapper, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t* num_creds_md, grpc_status_code* status,
const char** error_details);
explicit MetadataCredentialsPluginWrapper(
std::unique_ptr<MetadataCredentialsPlugin> plugin);
private:
void InvokePlugin(grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data);
void InvokePlugin(
grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void* user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t* num_creds_md, grpc_status_code* status_code,
const char** error_details);
std::unique_ptr<ThreadPoolInterface> thread_pool_;
std::unique_ptr<MetadataCredentialsPlugin> plugin_;
};

@ -61,12 +61,9 @@ namespace Grpc.Core.Internal
try
{
var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr),
Marshal.PtrToStringAnsi(methodNamePtr));
// Don't await, we are in a native callback and need to return.
#pragma warning disable 4014
GetMetadataAsync(context, callbackPtr, userDataPtr);
#pragma warning restore 4014
var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr), Marshal.PtrToStringAnsi(methodNamePtr));
// Make a guarantee that credentials_notify_from_plugin is invoked async to be compliant with c-core API.
ThreadPool.QueueUserWorkItem(async (stateInfo) => await GetMetadataAsync(context, callbackPtr, userDataPtr));
}
catch (Exception e)
{

@ -89,6 +89,54 @@ namespace Grpc.IntegrationTesting
client.UnaryCall(new SimpleRequest { }, new CallOptions(credentials: callCredentials));
}
[Test]
public async Task MetadataCredentials_Composed()
{
var first = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => {
// Attempt to exercise the case where async callback is inlineable/synchronously-runnable.
metadata.Add("first_authorization", "FIRST_SECRET_TOKEN");
return TaskUtils.CompletedTask;
}));
var second = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => {
metadata.Add("second_authorization", "SECOND_SECRET_TOKEN");
return TaskUtils.CompletedTask;
}));
var third = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => {
metadata.Add("third_authorization", "THIRD_SECRET_TOKEN");
return TaskUtils.CompletedTask;
}));
var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(),
CallCredentials.Compose(first, second, third));
channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
var client = new TestService.TestServiceClient(channel);
var call = client.StreamingOutputCall(new StreamingOutputCallRequest { });
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.IsFalse(await call.ResponseStream.MoveNext());
}
[Test]
public async Task MetadataCredentials_ComposedPerCall()
{
channel = new Channel(Host, server.Ports.Single().BoundPort, TestCredentials.CreateSslCredentials(), options);
var client = new TestService.TestServiceClient(channel);
var first = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => {
metadata.Add("first_authorization", "FIRST_SECRET_TOKEN");
return TaskUtils.CompletedTask;
}));
var second = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => {
metadata.Add("second_authorization", "SECOND_SECRET_TOKEN");
return TaskUtils.CompletedTask;
}));
var third = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => {
metadata.Add("third_authorization", "THIRD_SECRET_TOKEN");
return TaskUtils.CompletedTask;
}));
var call = client.StreamingOutputCall(new StreamingOutputCallRequest{ },
new CallOptions(credentials: CallCredentials.Compose(first, second, third)));
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.IsFalse(await call.ResponseStream.MoveNext());
}
[Test]
public void MetadataCredentials_InterceptorLeavesMetadataEmpty()
{
@ -125,6 +173,17 @@ namespace Grpc.IntegrationTesting
Assert.AreEqual("SECRET_TOKEN", authToken);
return Task.FromResult(new SimpleResponse());
}
public override async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
var first = context.RequestHeaders.First((entry) => entry.Key == "first_authorization").Value;
Assert.AreEqual("FIRST_SECRET_TOKEN", first);
var second = context.RequestHeaders.First((entry) => entry.Key == "second_authorization").Value;
Assert.AreEqual("SECOND_SECRET_TOKEN", second);
var third = context.RequestHeaders.First((entry) => entry.Key == "third_authorization").Value;
Assert.AreEqual("THIRD_SECRET_TOKEN", third);
await responseStream.WriteAsync(new StreamingOutputCallResponse());
}
}
}
}

@ -1023,13 +1023,17 @@ typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
grpc_credentials_plugin_metadata_cb cb, void *user_data,
int32_t is_destroy);
static void grpcsharp_get_metadata_handler(
static int grpcsharp_get_metadata_handler(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data) {
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(intptr_t)state;
interceptor(state, context.service_url, context.method_name, cb, user_data,
0);
return 0; /* Asynchronous return. */
}
static void grpcsharp_metadata_credentials_destroy_handler(void *state) {

@ -238,9 +238,12 @@ NAUV_WORK_CB(SendPluginCallback) {
}
}
void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
int plugin_get_metadata(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
plugin_state *p_state = reinterpret_cast<plugin_state *>(state);
plugin_callback_data *data = new plugin_callback_data;
data->service_url = context.service_url;
@ -252,6 +255,7 @@ void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
uv_mutex_unlock(&p_state->plugin_mutex);
uv_async_send(&p_state->plugin_async);
return 0; // Async processing.
}
void plugin_uv_close_cb(uv_handle_t *handle) {

@ -75,9 +75,11 @@ typedef struct plugin_state {
uv_async_t plugin_async;
} plugin_state;
void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data);
int plugin_get_metadata(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status, const char **error_details);
void plugin_destroy_state(void *state);

@ -35,6 +35,7 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/string_util.h>
zend_class_entry *grpc_ce_call_credentials;
#if PHP_MAJOR_VERSION >= 7
@ -143,9 +144,12 @@ PHP_METHOD(CallCredentials, createFromPlugin) {
}
/* Callback function for plugin creds API */
void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
int plugin_get_metadata(
void *ptr, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
TSRMLS_FETCH();
plugin_state *state = (plugin_state *)ptr;
@ -175,15 +179,19 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
/* call the user callback function */
zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
grpc_status_code code = GRPC_STATUS_OK;
*num_creds_md = 0;
*status = GRPC_STATUS_OK;
*error_details = NULL;
grpc_metadata_array metadata;
bool cleanup = true;
if (retval == NULL || Z_TYPE_P(retval) != IS_ARRAY) {
cleanup = false;
code = GRPC_STATUS_INVALID_ARGUMENT;
} else if (!create_metadata_array(retval, &metadata)) {
code = GRPC_STATUS_INVALID_ARGUMENT;
*status = GRPC_STATUS_INVALID_ARGUMENT;
return true; // Synchronous return.
}
if (!create_metadata_array(retval, &metadata)) {
*status = GRPC_STATUS_INVALID_ARGUMENT;
return true; // Synchronous return.
}
if (retval != NULL) {
@ -197,14 +205,24 @@ void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
#endif
}
/* Pass control back to core */
cb(user_data, metadata.metadata, metadata.count, code, NULL);
if (cleanup) {
for (int i = 0; i < metadata.count; i++) {
if (metadata.count > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
*status = GRPC_STATUS_INTERNAL;
*error_details = gpr_strdup(
"PHP plugin credentials returned too many metadata entries");
for (size_t i = 0; i < metadata.count; i++) {
// TODO(stanleycheung): Why don't we need to unref the key here?
grpc_slice_unref(metadata.metadata[i].value);
}
grpc_metadata_array_destroy(&metadata);
} else {
// Return data to core.
*num_creds_md = metadata.count;
for (size_t i = 0; i < metadata.count; ++i) {
creds_md[i] = metadata.metadata[i];
}
}
grpc_metadata_array_destroy(&metadata);
return true; // Synchronous return.
}
/* Cleanup function for plugin creds API */

@ -65,9 +65,12 @@ typedef struct plugin_state {
} plugin_state;
/* Callback function for plugin creds API */
void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data);
int plugin_get_metadata(
void *ptr, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details);
/* Cleanup function for plugin creds API */
void plugin_destroy_state(void *ptr);

@ -41,7 +41,8 @@ cdef class CredentialsMetadataPlugin:
cdef object plugin_callback
cdef bytes plugin_name
cdef grpc_metadata_credentials_plugin make_c_plugin(self)
cdef grpc_metadata_credentials_plugin _c_plugin(CredentialsMetadataPlugin plugin)
cdef class AuthMetadataContext:
@ -49,8 +50,11 @@ cdef class AuthMetadataContext:
cdef grpc_auth_metadata_context context
cdef void plugin_get_metadata(
cdef int plugin_get_metadata(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) with gil
cdef void plugin_destroy_c_plugin_state(void *state) with gil

@ -14,6 +14,7 @@
cimport cpython
import threading
import traceback
@ -89,20 +90,20 @@ cdef class CredentialsMetadataPlugin:
self.plugin_callback = plugin_callback
self.plugin_name = name
@staticmethod
cdef grpc_metadata_credentials_plugin make_c_plugin(self):
cdef grpc_metadata_credentials_plugin result
result.get_metadata = plugin_get_metadata
result.destroy = plugin_destroy_c_plugin_state
result.state = <void *>self
result.type = self.plugin_name
cpython.Py_INCREF(self)
return result
def __dealloc__(self):
grpc_shutdown()
cdef grpc_metadata_credentials_plugin _c_plugin(CredentialsMetadataPlugin plugin):
cdef grpc_metadata_credentials_plugin c_plugin
c_plugin.get_metadata = plugin_get_metadata
c_plugin.destroy = plugin_destroy_c_plugin_state
c_plugin.state = <void *>plugin
c_plugin.type = plugin.plugin_name
cpython.Py_INCREF(plugin)
return c_plugin
cdef class AuthMetadataContext:
def __cinit__(self):
@ -122,9 +123,12 @@ cdef class AuthMetadataContext:
grpc_shutdown()
cdef void plugin_get_metadata(
cdef int plugin_get_metadata(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) with gil:
called_flag = [False]
def python_callback(
Metadata metadata, grpc_status_code status,
@ -134,12 +138,15 @@ cdef void plugin_get_metadata(
cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state
cdef AuthMetadataContext cy_context = AuthMetadataContext()
cy_context.context = context
try:
self.plugin_callback(cy_context, python_callback)
except Exception as error:
if not called_flag[0]:
cb(user_data, NULL, 0, StatusCode.unknown,
traceback.format_exc().encode())
def async_callback():
try:
self.plugin_callback(cy_context, python_callback)
except Exception as error:
if not called_flag[0]:
cb(user_data, NULL, 0, StatusCode.unknown,
traceback.format_exc().encode())
threading.Thread(group=None, target=async_callback).start()
return 0 # Asynchronous return
cdef void plugin_destroy_c_plugin_state(void *state) with gil:
cpython.Py_DECREF(<CredentialsMetadataPlugin>state)
@ -239,7 +246,7 @@ def call_credentials_google_iam(authorization_token, authority_selector):
def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
cdef CallCredentials credentials = CallCredentials()
cdef grpc_metadata_credentials_plugin c_plugin = plugin.make_c_plugin()
cdef grpc_metadata_credentials_plugin c_plugin = _c_plugin(plugin)
with nogil:
credentials.c_credentials = (
grpc_metadata_credentials_create_from_plugin(c_plugin, NULL))

@ -375,6 +375,10 @@ cdef extern from "grpc/grpc.h":
cdef extern from "grpc/grpc_security.h":
# Declare this as an enum, this is the only way to make it a const in
# cython
enum: GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX
ctypedef enum grpc_ssl_roots_override_result:
GRPC_SSL_ROOTS_OVERRIDE_OK
GRPC_SSL_ROOTS_OVERRIDE_FAILED_PERMANENTLY
@ -462,9 +466,12 @@ cdef extern from "grpc/grpc_security.h":
grpc_status_code status, const char *error_details)
ctypedef struct grpc_metadata_credentials_plugin:
void (*get_metadata)(
int (*get_metadata)(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data)
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details)
void (*destroy)(void *state)
void *state
const char *type

@ -171,14 +171,6 @@ cdef class Timespec:
gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
return <double>real_time.seconds + <double>real_time.nanoseconds / 1e9
@staticmethod
def infinite_future():
return Timespec(float("+inf"))
@staticmethod
def infinite_past():
return Timespec(float("-inf"))
def __richcmp__(Timespec self not None, Timespec other not None, int op):
cdef gpr_timespec self_c_time = self.c_time
cdef gpr_timespec other_c_time = other.c_time
@ -454,7 +446,7 @@ cdef class _MetadataIterator:
self.i = self.i + 1
return result
else:
raise StopIteration
raise StopIteration()
# TODO(https://github.com/grpc/grpc/issues/7950): Eliminate this; just use an
@ -518,7 +510,7 @@ cdef class MetadataArray:
def __getitem__(self, size_t i):
if i >= self.c_metadata_array.count:
raise IndexError
raise IndexError()
key = _slice_bytes(self.c_metadata_array.metadata[i].key)
value = _slice_bytes(self.c_metadata_array.metadata[i].value)
return Metadatum(key=key, value=value)
@ -720,7 +712,7 @@ cdef class _OperationsIterator:
self.i = self.i + 1
return result
else:
raise StopIteration
raise StopIteration()
cdef class Operations:

@ -29,7 +29,7 @@ _SERIALIZED_RESPONSE = b'\x49\x50\x51'
_REQUEST_SERIALIZER = lambda unused_request: _SERIALIZED_REQUEST
_REQUEST_DESERIALIZER = lambda unused_serialized_request: object()
_RESPONSE_SERIALIZER = lambda unused_response: _SERIALIZED_RESPONSE
_RESPONSE_DESERIALIZER = lambda unused_serialized_resopnse: object()
_RESPONSE_DESERIALIZER = lambda unused_serialized_response: object()
_SERVICE = 'test.TestService'
_UNARY_UNARY = 'UnaryUnary'

@ -112,9 +112,12 @@ static void grpc_rb_call_credentials_callback_with_gil(void *param) {
gpr_free(params);
}
static void grpc_rb_call_credentials_plugin_get_metadata(
static int grpc_rb_call_credentials_plugin_get_metadata(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data) {
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
callback_params *params = gpr_malloc(sizeof(callback_params));
params->get_metadata = (VALUE)state;
params->context = context;
@ -123,6 +126,7 @@ static void grpc_rb_call_credentials_plugin_get_metadata(
grpc_rb_event_queue_enqueue(grpc_rb_call_credentials_callback_with_gil,
(void *)(params));
return 0; // Async return.
}
static void grpc_rb_call_credentials_plugin_destroy(void *state) {

@ -0,0 +1,4 @@
%YAML 1.2
--- |
<%namespace file="create_private_dns_zone_defs.include" import="*"/>\
${create_private_dns_zone(resolver_gce_integration_tests_zone_id, resolver_tests_common_zone_name)}

@ -0,0 +1,32 @@
<%def name="create_private_dns_zone(resolver_gce_integration_tests_zone_id, resolver_tests_common_zone_name)">#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
# This file is auto-generated
set -ex
cd $(dirname $0)/../../..
gcloud alpha dns managed-zones create \\
${resolver_gce_integration_tests_zone_id} \\
--dns-name=${resolver_tests_common_zone_name} \\
--description="GCE-DNS-private-zone-for-GRPC-testing" \\
--visibility=private \\
--networks=default</%def>

@ -0,0 +1,4 @@
%YAML 1.2
--- |
<%namespace file="private_dns_zone_init_defs.include" import="*"/>\
${private_dns_zone_init(all_integration_test_records, resolver_gce_integration_tests_zone_id, resolver_tests_common_zone_name)}

@ -0,0 +1,40 @@
<%def name="private_dns_zone_init(records,resolver_gce_integration_tests_zone_id,resolver_tests_common_zone_name)">#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
# This file is auto-generated
set -ex
cd $(dirname $0)/../../..
gcloud dns record-sets transaction start -z=${resolver_gce_integration_tests_zone_id}
% for r in records:
gcloud dns record-sets transaction add \\
-z=${resolver_gce_integration_tests_zone_id} \\
--name=${r['name']}.${resolver_tests_common_zone_name} \\
--type=${r['type']} \\
--ttl=${r['ttl']} \\
${r['data']}
% endfor
gcloud dns record-sets transaction describe -z=${resolver_gce_integration_tests_zone_id}
gcloud dns record-sets transaction execute -z=${resolver_gce_integration_tests_zone_id}
gcloud dns record-sets list -z=${resolver_gce_integration_tests_zone_id}</%def>

@ -0,0 +1,64 @@
<%def name="resolver_gce_integration_tests(tests, records, resolver_tests_common_zone_name)">#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
# This file is auto-generated
set -ex
if [[ "$GRPC_DNS_RESOLVER" == "" ]]; then
export GRPC_DNS_RESOLVER=ares
elif [[ "$GRPC_DNS_RESOLVER" != ares ]]; then
echo "Unexpected: GRPC_DNS_RESOLVER=$GRPC_DNS_RESOLVER. This test only works with c-ares resolver"
exit 1
fi
cd $(dirname $0)/../../..
if [[ "$CONFIG" == "" ]]; then
export CONFIG=opt
fi
make resolver_component_test
echo "Sanity check DNS records are resolveable with dig:"
EXIT_CODE=0
% for r in records:
ONE_FAILED=0
dig ${r['type']} ${r['name']}.${resolver_tests_common_zone_name} | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig ${r['type']} ${r['name']}.${resolver_tests_common_zone_name} FAILED"
exit 1
fi
% endfor
echo "Sanity check PASSED. Run resolver tests:"
% for test in tests:
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \\
--target_name='${test['target_name']}' \\
--expected_addrs='${test['expected_addrs']}' \\
--expected_chosen_service_config='${test['expected_chosen_service_config']}' \\
--expected_lb_policy='${test['expected_lb_policy']}' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: ${test['target_name']} FAILED"
EXIT_CODE=1
fi
% endfor
exit $EXIT_CODE</%def>

@ -0,0 +1,4 @@
%YAML 1.2
--- |
<%namespace file="resolver_gce_integration_tests_defs.include" import="*"/>\
${resolver_gce_integration_tests(resolver_gce_integration_test_cases, all_integration_test_records, resolver_tests_common_zone_name)}

@ -9,6 +9,6 @@ RUN apt-get update && apt-get install -y ${'\\'}
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -1036,39 +1036,46 @@ typedef enum {
static const expected_md plugin_md[] = {{"foo", "bar"}, {"hi", "there"}};
static void plugin_get_metadata_success(void *state,
grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
size_t i;
grpc_metadata md[GPR_ARRAY_SIZE(plugin_md)];
plugin_state *s = (plugin_state *)state;
static int plugin_get_metadata_success(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
GPR_ASSERT(strcmp(context.service_url, test_service_url) == 0);
GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
GPR_ASSERT(context.channel_auth_context == NULL);
GPR_ASSERT(context.reserved == NULL);
GPR_ASSERT(GPR_ARRAY_SIZE(plugin_md) <
GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX);
plugin_state *s = (plugin_state *)state;
*s = PLUGIN_GET_METADATA_CALLED_STATE;
for (i = 0; i < GPR_ARRAY_SIZE(plugin_md); i++) {
memset(&md[i], 0, sizeof(grpc_metadata));
md[i].key = grpc_slice_from_copied_string(plugin_md[i].key);
md[i].value = grpc_slice_from_copied_string(plugin_md[i].value);
for (size_t i = 0; i < GPR_ARRAY_SIZE(plugin_md); ++i) {
memset(&creds_md[i], 0, sizeof(grpc_metadata));
creds_md[i].key = grpc_slice_from_copied_string(plugin_md[i].key);
creds_md[i].value = grpc_slice_from_copied_string(plugin_md[i].value);
}
cb(user_data, md, GPR_ARRAY_SIZE(md), GRPC_STATUS_OK, NULL);
*num_creds_md = GPR_ARRAY_SIZE(plugin_md);
return true; // Synchronous return.
}
static const char *plugin_error_details = "Could not get metadata for plugin.";
static void plugin_get_metadata_failure(void *state,
grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb,
void *user_data) {
plugin_state *s = (plugin_state *)state;
static int plugin_get_metadata_failure(
void *state, grpc_auth_metadata_context context,
grpc_credentials_plugin_metadata_cb cb, void *user_data,
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
size_t *num_creds_md, grpc_status_code *status,
const char **error_details) {
GPR_ASSERT(strcmp(context.service_url, test_service_url) == 0);
GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
GPR_ASSERT(context.channel_auth_context == NULL);
GPR_ASSERT(context.reserved == NULL);
plugin_state *s = (plugin_state *)state;
*s = PLUGIN_GET_METADATA_CALLED_STATE;
cb(user_data, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, plugin_error_details);
*status = GRPC_STATUS_UNAUTHENTICATED;
*error_details = gpr_strdup(plugin_error_details);
return true; // Synchronous return.
}
static void plugin_destroy(void *state) {

@ -1673,6 +1673,34 @@ TEST_P(SecureEnd2endTest, BlockingAuthMetadataPluginFailure) {
kTestCredsPluginErrorMsg);
}
TEST_P(SecureEnd2endTest, CompositeCallCreds) {
ResetStub();
EchoRequest request;
EchoResponse response;
ClientContext context;
const char kMetadataKey1[] = "call-creds-key1";
const char kMetadataKey2[] = "call-creds-key2";
const char kMetadataVal1[] = "call-creds-val1";
const char kMetadataVal2[] = "call-creds-val2";
context.set_credentials(CompositeCallCredentials(
MetadataCredentialsFromPlugin(std::unique_ptr<MetadataCredentialsPlugin>(
new TestMetadataCredentialsPlugin(kMetadataKey1, kMetadataVal1, true,
true))),
MetadataCredentialsFromPlugin(std::unique_ptr<MetadataCredentialsPlugin>(
new TestMetadataCredentialsPlugin(kMetadataKey2, kMetadataVal2, true,
true)))));
request.set_message("Hello");
request.mutable_param()->set_echo_metadata(true);
Status s = stub_->Echo(&context, request, &response);
EXPECT_TRUE(s.ok());
EXPECT_TRUE(MetadataContains(context.GetServerTrailingMetadata(),
kMetadataKey1, kMetadataVal1));
EXPECT_TRUE(MetadataContains(context.GetServerTrailingMetadata(),
kMetadataKey2, kMetadataVal2));
}
TEST_P(SecureEnd2endTest, ClientAuthContext) {
ResetStub();
EchoRequest request;

@ -0,0 +1,43 @@
# Resolver Tests
This directory has tests and infrastructure for unit tests and GCE
integration tests of gRPC resolver functionality.
There are two different tests here:
## Resolver unit tests (resolver "component" tests)
These tests run per-change, along with the rest of the grpc unit tests.
They query a local testing DNS server.
## GCE integration tests
These tests use the same test binary and the same test records
as the unit tests, but they run against GCE DNS (this is done by
running the test on a GCE instance and not specifying an authority
in uris). These tests run in a background job, which needs to be
actively monitored.
## Making changes to test records
After making a change to `resolver_test_record_groups.yaml`:
1. Increment the "version number" in the `resolver_tests_common_zone_name`
DNS zone (this is a yaml field at the top
of `resolver_test_record_groups.yaml`).
2. Regenerate projects.
3. From the repo root, run:
```
$ test/cpp/naming/create_dns_private_zone.sh
$ test/cpp/naming/private_dns_zone_init.sh
```
Note that these commands must be ran in environment that
has access to the grpc-testing GCE project.
If everything runs smoothly, then once the change is merged,
the GCE DNS integration testing job will transition to the
new records and continue passing.

@ -0,0 +1,27 @@
#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
# This file is auto-generated
set -ex
cd $(dirname $0)/../../..
gcloud alpha dns managed-zones create \
resolver-tests-version-1-grpctestingexp-zone-id \
--dns-name=resolver-tests-version-1.grpctestingexp. \
--description="GCE-DNS-private-zone-for-GRPC-testing" \
--visibility=private \
--networks=default

@ -24,6 +24,12 @@ import json
_LOCAL_DNS_SERVER_ADDRESS = '127.0.0.1:15353'
_TARGET_RECORDS_TO_SKIP_AGAINST_GCE = [
# TODO: enable this once able to upload the very large TXT record
# in this group to GCE DNS.
'ipv4-config-causing-fallback-to-tcp',
]
def _append_zone_name(name, zone_name):
return '%s.%s' % (name, zone_name)
@ -33,21 +39,107 @@ def _build_expected_addrs_cmd_arg(expected_addrs):
out.append('%s,%s' % (addr['address'], str(addr['is_balancer'])))
return ';'.join(out)
def _data_for_type(r_type, r_data, common_zone_name):
if r_type in ['A', 'AAAA']:
return ' '.join(map(lambda x: '\"%s\"' % x, r_data))
if r_type == 'SRV':
assert len(r_data) == 1
target = r_data[0].split(' ')[3]
uploadable_target = '%s.%s' % (target, common_zone_name)
uploadable = r_data[0].split(' ')
uploadable[3] = uploadable_target
return '\"%s\"' % ' '.join(uploadable)
if r_type == 'TXT':
assert len(r_data) == 1
chunks = []
all_data = r_data[0]
cur = 0
# Split TXT records that span more than 255 characters (the single
# string length-limit in DNS) into multiple strings. Each string
# needs to be wrapped with double-quotes, and all inner double-quotes
# are escaped. The wrapping double-quotes and inner backslashes can be
# counted towards the 255 character length limit (as observed with gcloud),
# so make sure all strings fit within that limit.
while len(all_data[cur:]) > 0:
next_chunk = '\"'
while len(next_chunk) < 254 and len(all_data[cur:]) > 0:
if all_data[cur] == '\"':
if len(next_chunk) < 253:
next_chunk += '\\\"'
else:
break
else:
next_chunk += all_data[cur]
cur += 1
next_chunk += '\"'
if len(next_chunk) > 255:
raise Exception('Bug: next chunk is too long.')
chunks.append(next_chunk)
# Wrap the whole record in single quotes to make sure all strings
# are associated with the same TXT record (to make it one bash token for
# gcloud)
return '\'%s\'' % ' '.join(chunks)
# Convert DNS records from their "within a test group" format
# of the yaml file to an easier form for the templates to use.
def _gcloud_uploadable_form(test_cases, common_zone_name):
out = []
for group in test_cases:
if group['record_to_resolve'] in _TARGET_RECORDS_TO_SKIP_AGAINST_GCE:
continue
for record_name in group['records'].keys():
r_ttl = None
all_r_data = {}
for r_data in group['records'][record_name]:
# enforce records have the same TTL only for simplicity
if r_ttl is None:
r_ttl = r_data['TTL']
assert r_ttl == r_data['TTL'], '%s and %s differ' % (r_ttl, r_data['TTL'])
r_type = r_data['type']
if all_r_data.get(r_type) is None:
all_r_data[r_type] = []
all_r_data[r_type].append(r_data['data'])
for r_type in all_r_data.keys():
for r in out:
assert r['name'] != record_name or r['type'] != r_type, 'attempt to add a duplicate record'
out.append({
'name': record_name,
'ttl': r_ttl,
'type': r_type,
'data': _data_for_type(r_type, all_r_data[r_type], common_zone_name)
})
return out
def _gce_dns_zone_id(resolver_component_data):
dns_name = resolver_component_data['resolver_tests_common_zone_name']
return dns_name.replace('.', '-') + 'zone-id'
def _resolver_test_cases(resolver_component_data, records_to_skip):
out = []
for test_case in resolver_component_data['resolver_component_tests']:
if test_case['record_to_resolve'] in records_to_skip:
continue
out.append({
'target_name': _append_zone_name(test_case['record_to_resolve'],
resolver_component_data['resolver_tests_common_zone_name']),
'expected_addrs': _build_expected_addrs_cmd_arg(test_case['expected_addrs']),
'expected_chosen_service_config': (test_case['expected_chosen_service_config'] or ''),
'expected_lb_policy': (test_case['expected_lb_policy'] or ''),
})
return out
def main():
resolver_component_data = ''
with open('test/cpp/naming/resolver_test_record_groups.yaml') as f:
resolver_component_data = yaml.load(f)
json = {
'resolver_component_test_cases': [
{
'target_name': _append_zone_name(test_case['record_to_resolve'],
resolver_component_data['resolver_component_tests_common_zone_name']),
'expected_addrs': _build_expected_addrs_cmd_arg(test_case['expected_addrs']),
'expected_chosen_service_config': (test_case['expected_chosen_service_config'] or ''),
'expected_lb_policy': (test_case['expected_lb_policy'] or ''),
} for test_case in resolver_component_data['resolver_component_tests']
],
'resolver_tests_common_zone_name': resolver_component_data['resolver_tests_common_zone_name'],
'resolver_gce_integration_tests_zone_id': _gce_dns_zone_id(resolver_component_data),
'all_integration_test_records': _gcloud_uploadable_form(resolver_component_data['resolver_component_tests'],
resolver_component_data['resolver_tests_common_zone_name']),
'resolver_gce_integration_test_cases': _resolver_test_cases(resolver_component_data, _TARGET_RECORDS_TO_SKIP_AGAINST_GCE),
'resolver_component_test_cases': _resolver_test_cases(resolver_component_data, []),
'targets': [
{
'name': 'resolver_component_test' + unsecure_build_config_suffix,

@ -0,0 +1,215 @@
#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
# This file is auto-generated
set -ex
cd $(dirname $0)/../../..
gcloud dns record-sets transaction start -z=resolver-tests-version-1-grpctestingexp-zone-id
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv4-single-target.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 ipv4-single-target.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-single-target.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv4-multi-target.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 ipv4-multi-target.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-multi-target.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.5" "1.2.3.6" "1.2.3.7"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv6-single-target.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 ipv6-single-target.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv6-single-target.resolver-tests-version-1.grpctestingexp. \
--type=AAAA \
--ttl=2100 \
"2607:f8b0:400a:801::1001"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv6-multi-target.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 ipv6-multi-target.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv6-multi-target.resolver-tests-version-1.grpctestingexp. \
--type=AAAA \
--ttl=2100 \
"2607:f8b0:400a:801::1002" "2607:f8b0:400a:801::1003" "2607:f8b0:400a:801::1004"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. \
--type=TXT \
--ttl=2100 \
'"grpc_config=[{\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"SimpleService\",\"waitForReady\":true}]}]}}]"'
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. \
--type=TXT \
--ttl=2100 \
'"grpc_config=[{\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"NoSrvSimpleService\",\"waitForReady\":true}]}]}}]"'
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. \
--type=TXT \
--ttl=2100 \
'"grpc_config=[{\"clientLanguage\":[\"python\"],\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"PythonService\",\"waitForReady\":true}]}]}}]"'
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. \
--type=TXT \
--ttl=2100 \
'"grpc_config=[{\"percentage\":0,\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"CppService\",\"waitForReady\":true}]}]}}]"'
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. \
--type=TXT \
--ttl=2100 \
'"grpc_config=[{\"clientLanguage\":[\"go\"],\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"GoService\",\"waitForReady\":true}]}]}},{\"clientLanguage\":[\"c++\"],\"serviceConfig\":{" "\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"CppService\",\"waitForReady\":true}]}]}}]"'
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. \
--type=TXT \
--ttl=2100 \
'"grpc_config=[{\"percentage\":0,\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"NeverPickedService\",\"waitForReady\":true}]}]}},{\"percentage\":100,\"serviceConfig\":{\"loadBalanc" "ingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"method\":\"Foo\",\"service\":\"AlwaysPickedService\",\"waitForReady\":true}]}]}}]"'
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 balancer-for-ipv4-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=balancer-for-ipv4-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. \
--type=A \
--ttl=2100 \
"1.2.3.4"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=_grpclb._tcp.srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. \
--type=SRV \
--ttl=2100 \
"0 0 1234 balancer-for-ipv6-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp."
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=balancer-for-ipv6-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. \
--type=AAAA \
--ttl=2100 \
"2607:f8b0:400a:801::1002"
gcloud dns record-sets transaction add \
-z=resolver-tests-version-1-grpctestingexp-zone-id \
--name=srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. \
--type=AAAA \
--ttl=2100 \
"2607:f8b0:400a:801::1002"
gcloud dns record-sets transaction describe -z=resolver-tests-version-1-grpctestingexp-zone-id
gcloud dns record-sets transaction execute -z=resolver-tests-version-1-grpctestingexp-zone-id
gcloud dns record-sets list -z=resolver-tests-version-1-grpctestingexp-zone-id

@ -73,7 +73,7 @@ EXIT_CODE=0
# in the resolver.
$FLAGS_test_bin_path \
--target_name='srv-ipv4-single-target.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv4-single-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -81,7 +81,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='srv-ipv4-multi-target.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv4-multi-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.5:1234,True;1.2.3.6:1234,True;1.2.3.7:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -89,7 +89,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='srv-ipv6-single-target.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv6-single-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='[2607:f8b0:400a:801::1001]:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -97,7 +97,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='srv-ipv6-multi-target.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv6-multi-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1003]:1234,True;[2607:f8b0:400a:801::1004]:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -105,7 +105,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='srv-ipv4-simple-service-config.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:1234,True' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' \
@ -113,7 +113,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='ipv4-no-srv-simple-service-config.resolver-tests.grpctestingexp.' \
--target_name='ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' \
@ -121,7 +121,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='ipv4-no-config-for-cpp.resolver-tests.grpctestingexp.' \
--target_name='ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -129,7 +129,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='ipv4-cpp-config-has-zero-percentage.resolver-tests.grpctestingexp.' \
--target_name='ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -137,7 +137,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='ipv4-second-language-is-cpp.resolver-tests.grpctestingexp.' \
--target_name='ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' \
@ -145,7 +145,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='ipv4-config-with-percentages.resolver-tests.grpctestingexp.' \
--target_name='ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' \
@ -153,7 +153,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='srv-ipv4-target-has-backend-and-balancer.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:1234,True;1.2.3.4:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -161,7 +161,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='srv-ipv6-target-has-backend-and-balancer.resolver-tests.grpctestingexp.' \
--target_name='srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1002]:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' \
@ -169,7 +169,7 @@ $FLAGS_test_bin_path \
wait $! || EXIT_CODE=1
$FLAGS_test_bin_path \
--target_name='ipv4-config-causing-fallback-to-tcp.resolver-tests.grpctestingexp.' \
--target_name='ipv4-config-causing-fallback-to-tcp.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}' \
--expected_lb_policy='' \

@ -0,0 +1,359 @@
#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
# This file is auto-generated
set -ex
if [[ "$GRPC_DNS_RESOLVER" == "" ]]; then
export GRPC_DNS_RESOLVER=ares
elif [[ "$GRPC_DNS_RESOLVER" != ares ]]; then
echo "Unexpected: GRPC_DNS_RESOLVER=$GRPC_DNS_RESOLVER. This test only works with c-ares resolver"
exit 1
fi
cd $(dirname $0)/../../..
if [[ "$CONFIG" == "" ]]; then
export CONFIG=opt
fi
make resolver_component_test
echo "Sanity check DNS records are resolveable with dig:"
EXIT_CODE=0
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv4-single-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv4-single-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-single-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-single-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv4-multi-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv4-multi-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-multi-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-multi-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv6-single-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv6-single-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig AAAA ipv6-single-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig AAAA ipv6-single-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv6-multi-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv6-multi-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig AAAA ipv6-multi-target.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig AAAA ipv6-multi-target.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig TXT srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig TXT srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig TXT ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig TXT ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig TXT ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig TXT ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig TXT ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig TXT ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig TXT ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig TXT ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig TXT ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig TXT ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A balancer-for-ipv4-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A balancer-for-ipv4-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig A srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig A srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig SRV _grpclb._tcp.srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig SRV _grpclb._tcp.srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig AAAA balancer-for-ipv6-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig AAAA balancer-for-ipv6-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
ONE_FAILED=0
dig AAAA srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. | grep 'ANSWER SECTION' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Sanity check: dig AAAA srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
exit 1
fi
echo "Sanity check PASSED. Run resolver tests:"
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv4-single-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv4-single-target.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv4-multi-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.5:1234,True;1.2.3.6:1234,True;1.2.3.7:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv4-multi-target.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv6-single-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='[2607:f8b0:400a:801::1001]:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv6-single-target.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv6-multi-target.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1003]:1234,True;[2607:f8b0:400a:801::1004]:1234,True' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv6-multi-target.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:1234,True' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv4-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: ipv4-no-srv-simple-service-config.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: ipv4-no-config-for-cpp.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: ipv4-cpp-config-has-zero-percentage.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: ipv4-second-language-is-cpp.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:443,False' \
--expected_chosen_service_config='{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}' \
--expected_lb_policy='round_robin' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: ipv4-config-with-percentages.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='1.2.3.4:1234,True;1.2.3.4:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
ONE_FAILED=0
bins/$CONFIG/resolver_component_test \
--target_name='srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp.' \
--expected_addrs='[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1002]:443,False' \
--expected_chosen_service_config='' \
--expected_lb_policy='' || ONE_FAILED=1
if [[ "$ONE_FAILED" != 0 ]]; then
echo "Test based on target record: srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-1.grpctestingexp. FAILED"
EXIT_CODE=1
fi
exit $EXIT_CODE

@ -1,4 +1,4 @@
resolver_component_tests_common_zone_name: resolver-tests.grpctestingexp.
resolver_tests_common_zone_name: resolver-tests-version-1.grpctestingexp.
resolver_component_tests:
- expected_addrs:
- {address: '1.2.3.4:1234', is_balancer: true}

@ -66,7 +66,7 @@ def start_local_dns_server(args):
with open(args.records_config_path) as config:
test_records_config = yaml.load(config)
common_zone_name = test_records_config['resolver_component_tests_common_zone_name']
common_zone_name = test_records_config['resolver_tests_common_zone_name']
for group in test_records_config['resolver_component_tests']:
for name in group['records'].keys():
for record in group['records'][name]:

@ -0,0 +1,80 @@
#!/bin/bash
# Copyright 2017 gRPC authors.
#
# 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.
if [ "x$1" = "x" ] ; then
echo "Usage: $0 <first ref> [second ref]"
exit 1
else
first=$1
fi
if [ -n $2 ] ; then
second=HEAD
fi
if [ -e ~/github-credentials.vars ] ; then
. ~/github-credentials.vars
fi
if [ "x$github_client_id" = "x" ] || [ "x$github_client_secret" = "x" ] ; then
echo "Warning: you don't have github credentials set."
echo
echo "You may end up exceeding guest quota quickly."
echo "You can create an application for yourself,"
echo "and get its credentials. Go to"
echo
echo " https://github.com/settings/developers"
echo
echo "and click 'Register a new application'."
echo
echo "From the application's information, copy/paste"
echo "its Client ID and Client Secret, into the file"
echo
echo " ~/github-credentials.vars"
echo
echo "with the following format:"
echo
echo "github_client_id=0123456789abcdef0123"
echo "github_client_secret=0123456789abcdef0123456789abcdef"
echo
echo
addendum=""
else
addendum="?client_id=$github_client_id&client_secret=$github_client_secret"
fi
unset notfirst
echo "["
git log --pretty=oneline $1..$2 |
grep '[^ ]\+ Merge pull request #[0-9]\{4,6\} ' |
cut -f 2 -d# |
cut -f 1 -d\ |
sort -u |
while read id ; do
if [ "x$notfirst" = "x" ] ; then
notfirst=true
else
echo ","
fi
echo -n " {\"url\": \"https://github.com/grpc/grpc/pull/$id\","
out=`mktemp`
curl -s "https://api.github.com/repos/grpc/grpc/pulls/$id$addendum" > $out
echo -n " "`grep '"title"' $out`
echo -n " "`grep '"login"' $out | head -1`
echo -n " \"pr\": $id }"
rm $out
done
echo
echo "]"

@ -29,7 +29,7 @@ VIRTUALENV=python_pylint_venv
virtualenv $VIRTUALENV
PYTHON=$(realpath $VIRTUALENV/bin/python)
$PYTHON -m pip install --upgrade pip
$PYTHON -m pip install --upgrade pip==9.0.1
$PYTHON -m pip install pylint==1.6.5
for dir in "${DIRS[@]}"; do

@ -60,7 +60,7 @@ environment.update({
subprocess_arguments_list = [
{'args': ['virtualenv', VIRTUALENV_DIR], 'env': environment},
{'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip'],
{'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip==9.0.1'],
'env': environment},
{'args': [VIRTUALENV_PIP_PATH, 'install', '-r', REQUIREMENTS_PATH],
'env': environment},

@ -33,7 +33,7 @@ VIRTUALENV=yapf_virtual_environment
virtualenv $VIRTUALENV
PYTHON=$(realpath "${VIRTUALENV}/bin/python")
$PYTHON -m pip install --upgrade pip
$PYTHON -m pip install --upgrade pip==9.0.1
$PYTHON -m pip install --upgrade futures
$PYTHON -m pip install yapf==0.16.0

@ -60,7 +60,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -59,7 +59,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0

@ -60,7 +60,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -43,7 +43,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -43,7 +43,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -60,7 +60,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -60,7 +60,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -60,7 +60,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -36,7 +36,7 @@ RUN apk update && apk add \
zip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -121,7 +121,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -75,7 +75,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -75,7 +75,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -36,7 +36,7 @@ RUN apk update && apk add \
zip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -64,7 +64,7 @@ RUN apt-get update && apt-get install -y \
python-pip
# Install Python packages from PyPI
RUN pip install pip --upgrade
RUN pip install --upgrade pip==9.0.1
RUN pip install virtualenv
RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0

@ -72,6 +72,7 @@ sudo apt-get install -y netperf
sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
# Python dependencies
sudo pip install --upgrade pip==9.0.1
sudo pip install tabulate
sudo pip install google-api-python-client
sudo pip install virtualenv

@ -22,6 +22,8 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc
CPUS=`python -c 'import multiprocessing; print multiprocessing.cpu_count()'`
./tools/run_tests/start_port_server.py || true
make CONFIG=opt memory_profile_test memory_profile_client memory_profile_server -j $CPUS
bins/opt/memory_profile_test
bq load microbenchmarks.memory memory_usage.csv

@ -5,6 +5,21 @@ This directory contains scripts that facilitate building and running gRPC tests
The setup builds gRPC docker images for each language/runtime and upload it to Google Container Registry (GCR). These images, encapsulating gRPC stack
from specific releases/tag, are used to test version compatiblity between gRPC release versions.
## Step-by-step instructions for adding a new release to compatibility test
We have continuous nightly test setup to test gRPC backward compatibility between old clients and latest server. When a gRPC developer creates a new gRPC release, s/he is also responsible to add the just-released gRPC client to the nightly test. The steps are:
- Add (or update) an entry in ./client_matrix.py file to reference the github tag for the release.
- Build new client docker image(s). For example, for java release `v1.9.9`, do
- `tools/interop_matrix/create_matrix_images.py --git_checkout --release=v1.9.9 --language=java`
- Verify that the new docker image was built successfully and uploaded to GCR. For example,
- `gcloud beta container images list-tags gcr.io/grpc-testing/grpc_interop_java_oracle8`
- should show an image entry with tag `v1.9.9`.
- Verify the just-created docker client image would pass backward compatibility test (it should). For example,
- `gcloud docker -- pull gcr.io/grpc-testing/grpc_interop_java_oracle8:v1.9.9` followed by
- `docker_image=gcr.io/grpc-testing/grpc_interop_java_oracle8:v1.9.9 ./testcases/java__master`
- git commit the change and merge it to upstream/master.
- (Optional) clean up the tmp directory to where grpc source is cloned at `/export/hda3/tmp/grpc_matrix/`.
For more details on each step, refer to sections below.
## Instructions for creating GCR images
- Edit `./client_matrix.py` to include desired gRPC release.
- Run `tools/interop_matrix/create_matrix_images.py`. Useful options:
@ -45,3 +60,4 @@ For example:
Note:
- File path starting with `tools/` or `template/` are relative to the grpc repo root dir. File path starting with `./` are relative to current directory (`tools/interop_matrix`).
- Creating and referencing images in GCR require read and write permission to Google Container Registry path gcr.io/grpc-testing.

@ -29,4 +29,6 @@ fi
BENCHMARKS_TO_RUN="bm_fullstack_unary_ping_pong bm_fullstack_streaming_ping_pong bm_fullstack_streaming_pump bm_closure bm_cq bm_call_create bm_error bm_chttp2_hpack bm_chttp2_transport bm_pollset bm_metadata"
./tools/run_tests/start_port_server.py || true
$PYTHON tools/run_tests/run_microbenchmark.py --collect summary perf latency -b $BENCHMARKS_TO_RUN

@ -23,6 +23,7 @@ import bm_diff
import sys
import os
import random
import argparse
import multiprocessing
import subprocess
@ -32,6 +33,12 @@ sys.path.append(
os.path.dirname(sys.argv[0]), '..', '..', 'run_tests', 'python_utils'))
import comment_on_pr
sys.path.append(
os.path.join(
os.path.dirname(sys.argv[0]), '..', '..', '..', 'run_tests',
'python_utils'))
import jobset
def _args():
argp = argparse.ArgumentParser(
@ -125,8 +132,13 @@ def main(args):
subprocess.check_call(['git', 'checkout', where_am_i])
subprocess.check_call(['git', 'submodule', 'update'])
bm_run.run('new', args.benchmarks, args.jobs, args.loops, args.regex, args.counters)
bm_run.run(old, args.benchmarks, args.jobs, args.loops, args.regex, args.counters)
jobs_list = []
jobs_list += bm_run.create_jobs('new', args.benchmarks, args.loops, args.regex, args.counters)
jobs_list += bm_run.create_jobs(old, args.benchmarks, args.loops, args.regex, args.counters)
# shuffle all jobs to eliminate noise from GCE CPU drift
random.shuffle(jobs_list, random.SystemRandom().random)
jobset.run(jobs_list, maxjobs=args.jobs)
diff, note = bm_diff.diff(args.benchmarks, args.loops, args.regex, args.track, old,
'new', args.counters)

@ -95,11 +95,12 @@ def _collect_bm_data(bm, cfg, name, regex, idx, loops):
shortname='%s %s %s %s %d/%d' % (bm, line, cfg, name, idx + 1,
loops),
verbose_success=True,
cpu_cost=2,
timeout_seconds=60 * 60)) # one hour
return jobs_list
def run(name, benchmarks, jobs, loops, regex, counters):
def create_jobs(name, benchmarks, loops, regex, counters):
jobs_list = []
for loop in range(0, loops):
for bm in benchmarks:
@ -108,9 +109,11 @@ def run(name, benchmarks, jobs, loops, regex, counters):
jobs_list += _collect_bm_data(bm, 'counters', name, regex, loop,
loops)
random.shuffle(jobs_list, random.SystemRandom().random)
jobset.run(jobs_list, maxjobs=jobs)
return jobs_list
if __name__ == '__main__':
args = _args()
run(args.name, args.benchmarks, args.jobs, args.loops, args.regex, args.counters)
jobs_list = create_jobs(args.name, args.benchmarks, args.loops,
args.regex, args.counters)
jobset.run(jobs_list, maxjobs=args.jobs)

@ -152,7 +152,7 @@ pip_install_dir() {
cd $PWD
}
$VENV_PYTHON -m pip install --upgrade pip
$VENV_PYTHON -m pip install --upgrade pip==9.0.1
$VENV_PYTHON -m pip install setuptools
$VENV_PYTHON -m pip install cython
$VENV_PYTHON -m pip install six enum34 protobuf futures

@ -0,0 +1,28 @@
#!/bin/bash
# Copyright 2015 gRPC authors.
#
# 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.
#
# This script runs grpc/grpc-node tests with their grpc submodule updated
# to this reference
# cd to gRPC root directory
cd $(dirname $0)/../../..
CURRENT_COMMIT=$(git rev-parse --verify HEAD)
rm -rf ./../grpc-node
git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
cd ./../grpc-node
./test-grpc-submodule.sh $CURRENT_COMMIT

@ -47,7 +47,7 @@ class TestSuite:
_CORE_TEST_SUITE = TestSuite(['c'])
_CPP_TEST_SUITE = TestSuite(['c++'])
_CSHARP_TEST_SUITE = TestSuite(['csharp'])
_NODE_TEST_SUITE = TestSuite(['node'])
_NODE_TEST_SUITE = TestSuite(['node', 'grpc-node'])
_OBJC_TEST_SUITE = TestSuite(['objc'])
_PHP_TEST_SUITE = TestSuite(['php', 'php7'])
_PYTHON_TEST_SUITE = TestSuite(['python'])

@ -444,6 +444,67 @@ class CLanguage(object):
return self.make_target
# This tests Node on grpc/grpc-node and will become the standard for Node testing
class RemoteNodeLanguage(object):
def __init__(self):
self.platform = platform_string()
def configure(self, config, args):
self.config = config
self.args = args
# Note: electron ABI only depends on major and minor version, so that's all
# we should specify in the compiler argument
_check_compiler(self.args.compiler, ['default', 'node0.12',
'node4', 'node5', 'node6',
'node7', 'node8',
'electron1.3', 'electron1.6'])
if self.args.compiler == 'default':
self.runtime = 'node'
self.node_version = '8'
else:
if self.args.compiler.startswith('electron'):
self.runtime = 'electron'
self.node_version = self.args.compiler[8:]
else:
self.runtime = 'node'
# Take off the word "node"
self.node_version = self.args.compiler[4:]
# TODO: update with Windows/electron scripts when available for grpc/grpc-node
def test_specs(self):
if self.platform == 'windows':
return [self.config.job_spec(['tools\\run_tests\\helper_scripts\\run_node.bat'])]
else:
return [self.config.job_spec(['tools/run_tests/helper_scripts/run_grpc-node.sh'],
None,
environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
def pre_build_steps(self):
return []
def make_targets(self):
return []
def make_options(self):
return []
def build_steps(self):
return []
def post_tests_steps(self):
return []
def makefile_name(self):
return 'Makefile'
def dockerfile_dir(self):
return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(self.args.arch)
def __str__(self):
return 'grpc-node'
class NodeLanguage(object):
def __init__(self):
@ -1067,6 +1128,7 @@ with open('tools/run_tests/generated/configs.json') as f:
_LANGUAGES = {
'c++': CLanguage('cxx', 'c++'),
'c': CLanguage('c', 'c'),
'grpc-node': RemoteNodeLanguage(),
'node': NodeLanguage(),
'node_express': NodeExpressLanguage(),
'php': PhpLanguage(),

@ -169,7 +169,7 @@ def _create_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS):
inner_jobs=inner_jobs,
timeout_seconds=_CPP_RUNTESTS_TIMEOUT)
test_jobs += _generate_jobs(languages=['ruby', 'php'],
test_jobs += _generate_jobs(languages=['grpc-node', 'ruby', 'php'],
configs=['dbg', 'opt'],
platforms=['linux', 'macos'],
labels=['basictests', 'multilang'],

@ -25,7 +25,7 @@ sys.path.insert(0, os.path.abspath('tools/run_tests/'))
from run_tests_matrix import _create_test_jobs, _create_portability_test_jobs
import python_utils.filter_pull_request_tests as filter_pull_request_tests
_LIST_OF_LANGUAGE_LABELS = ['c', 'c++', 'csharp', 'node', 'objc', 'php', 'php7', 'python', 'ruby']
_LIST_OF_LANGUAGE_LABELS = ['c', 'c++', 'csharp', 'grpc-node', 'node', 'objc', 'php', 'php7', 'python', 'ruby']
_LIST_OF_PLATFORM_LABELS = ['linux', 'macos', 'windows']
class TestFilteringTest(unittest.TestCase):

Loading…
Cancel
Save