Skip to content
Snippets Groups Projects
Commit 2a3ec16a authored by Craig Tiller's avatar Craig Tiller
Browse files

Merge branch 'master' into release-0_10

parents 1199bfb2 d8539f01
No related branches found
No related tags found
No related merge requests found
Showing
with 559 additions and 156 deletions
...@@ -4,8 +4,8 @@ gens ...@@ -4,8 +4,8 @@ gens
libs libs
objs objs
# Python virtual environment (pre-3.4 only) # Python virtual environments
python2.7_virtual_environment python*_virtual_environment
# gcov coverage data # gcov coverage data
coverage coverage
......
...@@ -6,7 +6,8 @@ before_install: ...@@ -6,7 +6,8 @@ before_install:
- echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list - echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
- echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list - echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv clang-3.5 - sudo apt-get install -qq libgtest-dev libgflags-dev python-virtualenv python-dev python3-dev clang-3.5
- sudo pip install --upgrade virtualenv
- sudo pip install cpp-coveralls mako simplejson - sudo pip install cpp-coveralls mako simplejson
- sudo apt-get install -qq mono-devel nunit - sudo apt-get install -qq mono-devel nunit
- wget www.nuget.org/NuGet.exe -O nuget.exe - wget www.nuget.org/NuGet.exe -O nuget.exe
......
...@@ -51,6 +51,11 @@ typedef struct grpc_credentials grpc_credentials; ...@@ -51,6 +51,11 @@ typedef struct grpc_credentials grpc_credentials;
The creator of the credentials object is responsible for its release. */ The creator of the credentials object is responsible for its release. */
void grpc_credentials_release(grpc_credentials *creds); void grpc_credentials_release(grpc_credentials *creds);
/* Environment variable that points to the google default application
credentials json key or refresh token. Used in the
grpc_google_default_credentials_create function. */
#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
/* Creates default credentials to connect to a google gRPC service. /* Creates default credentials to connect to a google gRPC service.
WARNING: Do NOT use this credentials to connect to a non-google service as WARNING: Do NOT use this credentials to connect to a non-google service as
this could result in an oauth2 token leak. */ this could result in an oauth2 token leak. */
......
...@@ -111,10 +111,13 @@ void grpc_iomgr_shutdown(void) { ...@@ -111,10 +111,13 @@ void grpc_iomgr_shutdown(void) {
grpc_iomgr_closure *closure; grpc_iomgr_closure *closure;
gpr_timespec shutdown_deadline = gpr_timespec shutdown_deadline =
gpr_time_add(gpr_now(), gpr_time_from_seconds(10)); gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
gpr_timespec last_warning_time = gpr_now();
gpr_mu_lock(&g_mu); gpr_mu_lock(&g_mu);
g_shutdown = 1; g_shutdown = 1;
while (g_cbs_head != NULL || g_root_object.next != &g_root_object) { while (g_cbs_head != NULL || g_root_object.next != &g_root_object) {
if (gpr_time_cmp(gpr_time_sub(gpr_now(), last_warning_time),
gpr_time_from_seconds(1)) >= 0) {
if (g_cbs_head != NULL && g_root_object.next != &g_root_object) { if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"Waiting for %d iomgr objects to be destroyed and executing " "Waiting for %d iomgr objects to be destroyed and executing "
...@@ -126,6 +129,8 @@ void grpc_iomgr_shutdown(void) { ...@@ -126,6 +129,8 @@ void grpc_iomgr_shutdown(void) {
gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed", gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
count_objects()); count_objects());
} }
last_warning_time = gpr_now();
}
if (g_cbs_head) { if (g_cbs_head) {
do { do {
closure = g_cbs_head; closure = g_cbs_head;
......
...@@ -45,11 +45,14 @@ ...@@ -45,11 +45,14 @@
#include "src/core/iomgr/socket_windows.h" #include "src/core/iomgr/socket_windows.h"
grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) { grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) {
char *final_name;
grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket)); grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket));
memset(r, 0, sizeof(grpc_winsocket)); memset(r, 0, sizeof(grpc_winsocket));
r->socket = socket; r->socket = socket;
gpr_mu_init(&r->state_mu); gpr_mu_init(&r->state_mu);
grpc_iomgr_register_object(&r->iomgr_object, name); gpr_asprintf(&final_name, "%s:socket=0x%p", name, r);
grpc_iomgr_register_object(&r->iomgr_object, final_name);
gpr_free(final_name);
grpc_iocp_add_socket(r); grpc_iocp_add_socket(r);
return r; return r;
} }
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "src/core/json/json.h" #include "src/core/json/json.h"
#include "src/core/httpcli/httpcli.h" #include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr.h"
#include "src/core/security/json_token.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
...@@ -52,12 +51,12 @@ ...@@ -52,12 +51,12 @@
/* -- Common. -- */ /* -- Common. -- */
typedef struct { struct grpc_credentials_metadata_request {
grpc_credentials *creds; grpc_credentials *creds;
grpc_credentials_metadata_cb cb; grpc_credentials_metadata_cb cb;
grpc_iomgr_closure *on_simulated_token_fetch_done_closure; grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
void *user_data; void *user_data;
} grpc_credentials_metadata_request; };
static grpc_credentials_metadata_request * static grpc_credentials_metadata_request *
grpc_credentials_metadata_request_create(grpc_credentials *creds, grpc_credentials_metadata_request_create(grpc_credentials *creds,
...@@ -152,16 +151,6 @@ grpc_security_status grpc_server_credentials_create_security_connector( ...@@ -152,16 +151,6 @@ grpc_security_status grpc_server_credentials_create_security_connector(
/* -- Ssl credentials. -- */ /* -- Ssl credentials. -- */
typedef struct {
grpc_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
static void ssl_destroy(grpc_credentials *creds) { static void ssl_destroy(grpc_credentials *creds) {
grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
...@@ -326,22 +315,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( ...@@ -326,22 +315,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create(
/* -- Jwt credentials -- */ /* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
/* Have a simple cache for now with just 1 entry. We could have a map based on
the service_url for a more sophisticated one. */
gpr_mu cache_mu;
struct {
grpc_credentials_md_store *jwt_md;
char *service_url;
gpr_timespec jwt_expiration;
} cached;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
static void jwt_reset_cache(grpc_jwt_credentials *c) { static void jwt_reset_cache(grpc_jwt_credentials *c) {
if (c->cached.jwt_md != NULL) { if (c->cached.jwt_md != NULL) {
grpc_credentials_md_store_unref(c->cached.jwt_md); grpc_credentials_md_store_unref(c->cached.jwt_md);
...@@ -424,10 +397,9 @@ static grpc_credentials_vtable jwt_vtable = { ...@@ -424,10 +397,9 @@ static grpc_credentials_vtable jwt_vtable = {
jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
jwt_get_request_metadata, NULL}; jwt_get_request_metadata, NULL};
grpc_credentials *grpc_jwt_credentials_create(const char *json_key, grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
gpr_timespec token_lifetime) { grpc_auth_json_key key, gpr_timespec token_lifetime) {
grpc_jwt_credentials *c; grpc_jwt_credentials *c;
grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
if (!grpc_auth_json_key_is_valid(&key)) { if (!grpc_auth_json_key_is_valid(&key)) {
gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
return NULL; return NULL;
...@@ -444,25 +416,13 @@ grpc_credentials *grpc_jwt_credentials_create(const char *json_key, ...@@ -444,25 +416,13 @@ grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
return &c->base; return &c->base;
} }
/* -- Oauth2TokenFetcher credentials -- */ grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) {
/* This object is a base for credentials that need to acquire an oauth2 token return grpc_jwt_credentials_create_from_auth_json_key(
from an http service. */ grpc_auth_json_key_create_from_string(json_key), token_lifetime);
}
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb,
gpr_timespec deadline);
typedef struct { /* -- Oauth2TokenFetcher credentials -- */
grpc_credentials base;
gpr_mu mu;
grpc_credentials_md_store *access_token_md;
gpr_timespec token_expiration;
grpc_httpcli_context httpcli_context;
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
static void oauth2_token_fetcher_destroy(grpc_credentials *creds) { static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
grpc_oauth2_token_fetcher_credentials *c = grpc_oauth2_token_fetcher_credentials *c =
...@@ -669,13 +629,6 @@ grpc_credentials *grpc_compute_engine_credentials_create(void) { ...@@ -669,13 +629,6 @@ grpc_credentials *grpc_compute_engine_credentials_create(void) {
/* -- ServiceAccount credentials. -- */ /* -- ServiceAccount credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_json_key key;
char *scope;
gpr_timespec token_lifetime;
} grpc_service_account_credentials;
static void service_account_destroy(grpc_credentials *creds) { static void service_account_destroy(grpc_credentials *creds) {
grpc_service_account_credentials *c = grpc_service_account_credentials *c =
(grpc_service_account_credentials *)creds; (grpc_service_account_credentials *)creds;
...@@ -746,11 +699,6 @@ grpc_credentials *grpc_service_account_credentials_create( ...@@ -746,11 +699,6 @@ grpc_credentials *grpc_service_account_credentials_create(
/* -- RefreshToken credentials. -- */ /* -- RefreshToken credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
} grpc_refresh_token_credentials;
static void refresh_token_destroy(grpc_credentials *creds) { static void refresh_token_destroy(grpc_credentials *creds) {
grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds; grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
grpc_auth_refresh_token_destruct(&c->refresh_token); grpc_auth_refresh_token_destruct(&c->refresh_token);
...@@ -786,12 +734,9 @@ static void refresh_token_fetch_oauth2( ...@@ -786,12 +734,9 @@ static void refresh_token_fetch_oauth2(
gpr_free(body); gpr_free(body);
} }
grpc_credentials *grpc_refresh_token_credentials_create( grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
const char *json_refresh_token) { grpc_auth_refresh_token refresh_token) {
grpc_refresh_token_credentials *c; grpc_refresh_token_credentials *c;
grpc_auth_refresh_token refresh_token =
grpc_auth_refresh_token_create_from_string(json_refresh_token);
if (!grpc_auth_refresh_token_is_valid(&refresh_token)) { if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation"); gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
return NULL; return NULL;
...@@ -804,13 +749,13 @@ grpc_credentials *grpc_refresh_token_credentials_create( ...@@ -804,13 +749,13 @@ grpc_credentials *grpc_refresh_token_credentials_create(
return &c->base.base; return &c->base.base;
} }
/* -- Fake Oauth2 credentials. -- */ grpc_credentials *grpc_refresh_token_credentials_create(
const char *json_refresh_token) {
return grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token_create_from_string(json_refresh_token));
}
typedef struct { /* -- Fake Oauth2 credentials. -- */
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
int is_async;
} grpc_fake_oauth2_credentials;
static void fake_oauth2_destroy(grpc_credentials *creds) { static void fake_oauth2_destroy(grpc_credentials *creds) {
grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
...@@ -877,11 +822,6 @@ grpc_credentials *grpc_fake_oauth2_credentials_create( ...@@ -877,11 +822,6 @@ grpc_credentials *grpc_fake_oauth2_credentials_create(
/* -- Oauth2 Access Token credentials. -- */ /* -- Oauth2 Access Token credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
} grpc_access_token_credentials;
static void access_token_destroy(grpc_credentials *creds) { static void access_token_destroy(grpc_credentials *creds) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds; grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
grpc_credentials_md_store_unref(c->access_token_md); grpc_credentials_md_store_unref(c->access_token_md);
...@@ -996,12 +936,6 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( ...@@ -996,12 +936,6 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
/* -- Composite credentials. -- */ /* -- Composite credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials;
typedef struct { typedef struct {
grpc_composite_credentials *composite_creds; grpc_composite_credentials *composite_creds;
size_t creds_index; size_t creds_index;
...@@ -1232,11 +1166,6 @@ grpc_credentials *grpc_credentials_contains_type( ...@@ -1232,11 +1166,6 @@ grpc_credentials *grpc_credentials_contains_type(
/* -- IAM credentials. -- */ /* -- IAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
} grpc_iam_credentials;
static void iam_destroy(grpc_credentials *creds) { static void iam_destroy(grpc_credentials *creds) {
grpc_iam_credentials *c = (grpc_iam_credentials *)creds; grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
grpc_credentials_md_store_unref(c->iam_md); grpc_credentials_md_store_unref(c->iam_md);
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include <grpc/grpc_security.h> #include <grpc/grpc_security.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include "src/core/httpcli/httpcli.h"
#include "src/core/security/json_token.h"
#include "src/core/security/security_connector.h" #include "src/core/security/security_connector.h"
struct grpc_httpcli_response; struct grpc_httpcli_response;
...@@ -178,11 +180,22 @@ grpc_credentials_status ...@@ -178,11 +180,22 @@ grpc_credentials_status
grpc_oauth2_token_fetcher_credentials_parse_server_response( grpc_oauth2_token_fetcher_credentials_parse_server_response(
const struct grpc_httpcli_response *response, const struct grpc_httpcli_response *response,
grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
void grpc_flush_cached_google_default_credentials(void);
/* Simulates an oauth2 token fetch with the specified value for testing. */ /* Simulates an oauth2 token fetch with the specified value for testing. */
grpc_credentials *grpc_fake_oauth2_credentials_create( grpc_credentials *grpc_fake_oauth2_credentials_create(
const char *token_md_value, int is_async); const char *token_md_value, int is_async);
/* Private constructor for jwt credentials from an already parsed json key.
Takes ownership of the key. */
grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
grpc_auth_json_key key, gpr_timespec token_lifetime);
/* Private constructor for refresh token credentials from an already parsed
refresh token. Takes ownership of the refresh token. */
grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token token);
/* --- grpc_server_credentials. --- */ /* --- grpc_server_credentials. --- */
typedef struct { typedef struct {
...@@ -199,4 +212,103 @@ struct grpc_server_credentials { ...@@ -199,4 +212,103 @@ struct grpc_server_credentials {
grpc_security_status grpc_server_credentials_create_security_connector( grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc); grpc_server_credentials *creds, grpc_security_connector **sc);
/* -- Ssl credentials. -- */
typedef struct {
grpc_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
/* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
/* Have a simple cache for now with just 1 entry. We could have a map based on
the service_url for a more sophisticated one. */
gpr_mu cache_mu;
struct {
grpc_credentials_md_store *jwt_md;
char *service_url;
gpr_timespec jwt_expiration;
} cached;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
/* -- Oauth2TokenFetcher credentials --
This object is a base for credentials that need to acquire an oauth2 token
from an http service. */
typedef struct grpc_credentials_metadata_request
grpc_credentials_metadata_request;
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb,
gpr_timespec deadline);
typedef struct {
grpc_credentials base;
gpr_mu mu;
grpc_credentials_md_store *access_token_md;
gpr_timespec token_expiration;
grpc_httpcli_context httpcli_context;
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
/* -- ServiceAccount credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_json_key key;
char *scope;
gpr_timespec token_lifetime;
} grpc_service_account_credentials;
/* -- RefreshToken credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
} grpc_refresh_token_credentials;
/* -- Oauth2 Access Token credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
} grpc_access_token_credentials;
/* -- Fake Oauth2 credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
int is_async;
} grpc_fake_oauth2_credentials;
/* -- IAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
} grpc_iam_credentials;
/* -- Composite credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials;
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */ #endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
/* -- Constants. -- */ /* -- Constants. -- */
#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal" #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
/* -- Default credentials. -- */ /* -- Default credentials. -- */
...@@ -123,36 +122,40 @@ static int is_stack_running_on_compute_engine(void) { ...@@ -123,36 +122,40 @@ static int is_stack_running_on_compute_engine(void) {
} }
/* Takes ownership of creds_path if not NULL. */ /* Takes ownership of creds_path if not NULL. */
static grpc_credentials *create_jwt_creds_from_path(char *creds_path) { static grpc_credentials *create_default_creds_from_path(char *creds_path) {
grpc_json *json = NULL;
grpc_auth_json_key key;
grpc_auth_refresh_token token;
grpc_credentials *result = NULL; grpc_credentials *result = NULL;
gpr_slice creds_data; gpr_slice creds_data = gpr_empty_slice();
int file_ok = 0; int file_ok = 0;
if (creds_path == NULL) return NULL; if (creds_path == NULL) goto end;
creds_data = gpr_load_file(creds_path, 1, &file_ok); creds_data = gpr_load_file(creds_path, 0, &file_ok);
gpr_free(creds_path); if (!file_ok) goto end;
if (file_ok) { json = grpc_json_parse_string_with_len(
result = grpc_jwt_credentials_create( (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data));
(const char *)GPR_SLICE_START_PTR(creds_data), if (json == NULL) goto end;
grpc_max_auth_token_lifetime);
gpr_slice_unref(creds_data); /* First, try an auth json key. */
key = grpc_auth_json_key_create_from_json(json);
if (grpc_auth_json_key_is_valid(&key)) {
result = grpc_jwt_credentials_create_from_auth_json_key(
key, grpc_max_auth_token_lifetime);
goto end;
} }
return result;
/* Then try a refresh token if the auth json key was invalid. */
token = grpc_auth_refresh_token_create_from_json(json);
if (grpc_auth_refresh_token_is_valid(&token)) {
result =
grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
goto end;
} }
/* Takes ownership of creds_path if not NULL. */ end:
static grpc_credentials *create_refresh_token_creds_from_path( if (creds_path != NULL) gpr_free(creds_path);
char *creds_path) {
grpc_credentials *result = NULL;
gpr_slice creds_data;
int file_ok = 0;
if (creds_path == NULL) return NULL;
creds_data = gpr_load_file(creds_path, 1, &file_ok);
gpr_free(creds_path);
if (file_ok) {
result = grpc_refresh_token_credentials_create(
(const char *)GPR_SLICE_START_PTR(creds_data));
gpr_slice_unref(creds_data); gpr_slice_unref(creds_data);
} if (json != NULL) grpc_json_destroy(json);
return result; return result;
} }
...@@ -170,12 +173,12 @@ grpc_credentials *grpc_google_default_credentials_create(void) { ...@@ -170,12 +173,12 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
} }
/* First, try the environment variable. */ /* First, try the environment variable. */
result = result = create_default_creds_from_path(
create_jwt_creds_from_path(gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR)); gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
if (result != NULL) goto end; if (result != NULL) goto end;
/* Then the well-known file. */ /* Then the well-known file. */
result = create_refresh_token_creds_from_path( result = create_default_creds_from_path(
grpc_get_well_known_google_credentials_file_path()); grpc_get_well_known_google_credentials_file_path());
if (result != NULL) goto end; if (result != NULL) goto end;
...@@ -193,11 +196,24 @@ end: ...@@ -193,11 +196,24 @@ end:
if (!serving_cached_credentials && result != NULL) { if (!serving_cached_credentials && result != NULL) {
/* Blend with default ssl credentials and add a global reference so that it /* Blend with default ssl credentials and add a global reference so that it
can be cached and re-served. */ can be cached and re-served. */
result = grpc_composite_credentials_create( grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
grpc_ssl_credentials_create(NULL, NULL), result); default_credentials = grpc_credentials_ref(grpc_composite_credentials_create(
GPR_ASSERT(result != NULL); ssl_creds, result));
default_credentials = grpc_credentials_ref(result); GPR_ASSERT(default_credentials != NULL);
grpc_credentials_unref(ssl_creds);
grpc_credentials_unref(result);
result = default_credentials;
} }
gpr_mu_unlock(&g_mu); gpr_mu_unlock(&g_mu);
return result; return result;
} }
void grpc_flush_cached_google_default_credentials(void) {
gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_mu);
if (default_credentials != NULL) {
grpc_credentials_unref(default_credentials);
default_credentials = NULL;
}
gpr_mu_unlock(&g_mu);
}
...@@ -46,17 +46,11 @@ ...@@ -46,17 +46,11 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include "src/core/json/json.h"
/* --- Constants. --- */ /* --- Constants. --- */
/* 1 hour max. */ /* 1 hour max. */
const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0}; const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0};
#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
#define GRPC_JWT_TYPE "JWT" #define GRPC_JWT_TYPE "JWT"
...@@ -66,7 +60,7 @@ static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL; ...@@ -66,7 +60,7 @@ static grpc_jwt_encode_and_sign_override g_jwt_encode_and_sign_override = NULL;
/* --- grpc_auth_json_key. --- */ /* --- grpc_auth_json_key. --- */
static const char *json_get_string_property(grpc_json *json, static const char *json_get_string_property(const grpc_json *json,
const char *prop_name) { const char *prop_name) {
grpc_json *child; grpc_json *child;
for (child = json->child; child != NULL; child = child->next) { for (child = json->child; child != NULL; child = child->next) {
...@@ -79,7 +73,8 @@ static const char *json_get_string_property(grpc_json *json, ...@@ -79,7 +73,8 @@ static const char *json_get_string_property(grpc_json *json,
return child->value; return child->value;
} }
static int set_json_key_string_property(grpc_json *json, const char *prop_name, static int set_json_key_string_property(const grpc_json *json,
const char *prop_name,
char **json_key_field) { char **json_key_field) {
const char *prop_value = json_get_string_property(json, prop_name); const char *prop_value = json_get_string_property(json, prop_name);
if (prop_value == NULL) return 0; if (prop_value == NULL) return 0;
...@@ -92,11 +87,8 @@ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) { ...@@ -92,11 +87,8 @@ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID); strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
} }
grpc_auth_json_key grpc_auth_json_key_create_from_string( grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json) {
const char *json_string) {
grpc_auth_json_key result; grpc_auth_json_key result;
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
BIO *bio = NULL; BIO *bio = NULL;
const char *prop_value; const char *prop_value;
int success = 0; int success = 0;
...@@ -104,7 +96,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string( ...@@ -104,7 +96,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
memset(&result, 0, sizeof(grpc_auth_json_key)); memset(&result, 0, sizeof(grpc_auth_json_key));
result.type = GRPC_AUTH_JSON_TYPE_INVALID; result.type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json == NULL) { if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string); gpr_log(GPR_ERROR, "Invalid json.");
goto end; goto end;
} }
...@@ -142,8 +134,16 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string( ...@@ -142,8 +134,16 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
end: end:
if (bio != NULL) BIO_free(bio); if (bio != NULL) BIO_free(bio);
if (json != NULL) grpc_json_destroy(json);
if (!success) grpc_auth_json_key_destruct(&result); if (!success) grpc_auth_json_key_destruct(&result);
return result;
}
grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string) {
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
grpc_auth_json_key result = grpc_auth_json_key_create_from_json(json);
if (json != NULL) grpc_json_destroy(json);
gpr_free(scratchpad); gpr_free(scratchpad);
return result; return result;
} }
...@@ -342,18 +342,16 @@ int grpc_auth_refresh_token_is_valid( ...@@ -342,18 +342,16 @@ int grpc_auth_refresh_token_is_valid(
strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID); strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
} }
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
const char *json_string) { const grpc_json *json) {
grpc_auth_refresh_token result; grpc_auth_refresh_token result;
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
const char *prop_value; const char *prop_value;
int success = 0; int success = 0;
memset(&result, 0, sizeof(grpc_auth_refresh_token)); memset(&result, 0, sizeof(grpc_auth_refresh_token));
result.type = GRPC_AUTH_JSON_TYPE_INVALID; result.type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json == NULL) { if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string); gpr_log(GPR_ERROR, "Invalid json.");
goto end; goto end;
} }
...@@ -374,8 +372,17 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( ...@@ -374,8 +372,17 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
success = 1; success = 1;
end: end:
if (json != NULL) grpc_json_destroy(json);
if (!success) grpc_auth_refresh_token_destruct(&result); if (!success) grpc_auth_refresh_token_destruct(&result);
return result;
}
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
const char *json_string) {
char *scratchpad = gpr_strdup(json_string);
grpc_json *json = grpc_json_parse_string(scratchpad);
grpc_auth_refresh_token result =
grpc_auth_refresh_token_create_from_json(json);
if (json != NULL) grpc_json_destroy(json);
gpr_free(scratchpad); gpr_free(scratchpad);
return result; return result;
} }
......
...@@ -37,10 +37,16 @@ ...@@ -37,10 +37,16 @@
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include "src/core/json/json.h"
/* --- Constants. --- */ /* --- Constants. --- */
#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" #define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token"
#define GRPC_AUTH_JSON_TYPE_INVALID "invalid"
#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
/* --- auth_json_key parsing. --- */ /* --- auth_json_key parsing. --- */
typedef struct { typedef struct {
...@@ -59,6 +65,10 @@ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key); ...@@ -59,6 +65,10 @@ int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key);
grpc_auth_json_key grpc_auth_json_key_create_from_string( grpc_auth_json_key grpc_auth_json_key_create_from_string(
const char *json_string); const char *json_string);
/* Creates a json_key object from parsed json. Returns an invalid object if a
parsing error has been encountered. */
grpc_auth_json_key grpc_auth_json_key_create_from_json(const grpc_json *json);
/* Destructs the object. */ /* Destructs the object. */
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key); void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key);
...@@ -97,6 +107,11 @@ int grpc_auth_refresh_token_is_valid( ...@@ -97,6 +107,11 @@ int grpc_auth_refresh_token_is_valid(
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string( grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
const char *json_string); const char *json_string);
/* Creates a refresh token object from parsed json. Returns an invalid object if
a parsing error has been encountered. */
grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json(
const grpc_json *json);
/* Destructs the object. */ /* Destructs the object. */
void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token); void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
......
...@@ -166,6 +166,9 @@ struct grpc_server { ...@@ -166,6 +166,9 @@ struct grpc_server {
listener *listeners; listener *listeners;
int listeners_destroyed; int listeners_destroyed;
gpr_refcount internal_refcount; gpr_refcount internal_refcount;
/** when did we print the last shutdown progress message */
gpr_timespec last_shutdown_message_time;
}; };
typedef enum { typedef enum {
...@@ -441,7 +444,7 @@ static void start_new_rpc(grpc_call_element *elem) { ...@@ -441,7 +444,7 @@ static void start_new_rpc(grpc_call_element *elem) {
/* TODO(ctiller): unify these two searches */ /* TODO(ctiller): unify these two searches */
/* check for an exact match with host */ /* check for an exact match with host */
hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash); hash = GRPC_MDSTR_KV_HASH(calld->host->hash, calld->path->hash);
for (i = 0; i < chand->registered_method_max_probes; i++) { for (i = 0; i <= chand->registered_method_max_probes; i++) {
rm = &chand->registered_methods[(hash + i) % rm = &chand->registered_methods[(hash + i) %
chand->registered_method_slots]; chand->registered_method_slots];
if (!rm) break; if (!rm) break;
...@@ -481,20 +484,35 @@ static int num_listeners(grpc_server *server) { ...@@ -481,20 +484,35 @@ static int num_listeners(grpc_server *server) {
return n; return n;
} }
static int num_channels(grpc_server *server) {
channel_data *chand;
int n = 0;
for (chand = server->root_channel_data.next;
chand != &server->root_channel_data; chand = chand->next) {
n++;
}
return n;
}
static void maybe_finish_shutdown(grpc_server *server) { static void maybe_finish_shutdown(grpc_server *server) {
size_t i; size_t i;
if (!server->shutdown || server->shutdown_published) { if (!server->shutdown || server->shutdown_published) {
return; return;
} }
if (server->root_channel_data.next != &server->root_channel_data) { if (server->root_channel_data.next != &server->root_channel_data ||
server->listeners_destroyed < num_listeners(server)) {
if (gpr_time_cmp(
gpr_time_sub(gpr_now(), server->last_shutdown_message_time),
gpr_time_from_seconds(1)) >= 0) {
server->last_shutdown_message_time = gpr_now();
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"Waiting for all channels to close before destroying server"); "Waiting for %d channels and %d/%d listeners to be destroyed"
return; " before shutting down server",
num_channels(server),
num_listeners(server) - server->listeners_destroyed,
num_listeners(server));
} }
if (server->listeners_destroyed < num_listeners(server)) {
gpr_log(GPR_DEBUG, "Waiting for all listeners to be destroyed (@ %d/%d)",
server->listeners_destroyed, num_listeners(server));
return; return;
} }
server->shutdown_published = 1; server->shutdown_published = 1;
...@@ -944,6 +962,8 @@ void grpc_server_shutdown_and_notify(grpc_server *server, ...@@ -944,6 +962,8 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
return; return;
} }
server->last_shutdown_message_time = gpr_now();
channel_broadcaster_init(server, &broadcaster); channel_broadcaster_init(server, &broadcaster);
/* collect all unregistered then registered calls */ /* collect all unregistered then registered calls */
......
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
'use strict';
var grpc = require('../');
var _ = require('lodash');
var health_proto = grpc.load(__dirname + '/health.proto');
var HealthClient = health_proto.grpc.health.v1alpha.Health;
function HealthImplementation(statusMap) {
this.statusMap = _.clone(statusMap);
}
HealthImplementation.prototype.setStatus = function(host, service, status) {
if (!this.statusMap[host]) {
this.statusMap[host] = {};
}
this.statusMap[host][service] = status;
};
HealthImplementation.prototype.check = function(call, callback){
var host = call.request.host;
var service = call.request.service;
var status = _.get(this.statusMap, [host, service], null);
if (status === null) {
callback({code:grpc.status.NOT_FOUND});
} else {
callback(null, {status: status});
}
};
module.exports = {
Client: HealthClient,
service: HealthClient.service,
Implementation: HealthImplementation
};
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package grpc.health.v1alpha;
message HealthCheckRequest {
string host = 1;
string service = 2;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
}
ServingStatus status = 1;
}
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
}
\ No newline at end of file
...@@ -634,7 +634,8 @@ function makeServerConstructor(service_attr_map) { ...@@ -634,7 +634,8 @@ function makeServerConstructor(service_attr_map) {
} }
var serialize = attrs.responseSerialize; var serialize = attrs.responseSerialize;
var deserialize = attrs.requestDeserialize; var deserialize = attrs.requestDeserialize;
server.register(attrs.path, service_handlers[service_name][name], server.register(attrs.path, _.bind(service_handlers[service_name][name],
service_handlers[service_name]),
serialize, deserialize, method_type); serialize, deserialize, method_type);
}); });
}, this); }, this);
......
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
'use strict';
var assert = require('assert');
var health = require('../health_check/health.js');
var grpc = require('../');
describe('Health Checking', function() {
var statusMap = {
'': {
'': 'SERVING',
'grpc.test.TestService': 'NOT_SERVING',
},
virtual_host: {
'grpc.test.TestService': 'SERVING'
}
};
var HealthServer = grpc.buildServer([health.service]);
var healthServer = new HealthServer({
'grpc.health.v1alpha.Health': new health.Implementation(statusMap)
});
var healthClient;
before(function() {
var port_num = healthServer.bind('0.0.0.0:0');
healthServer.listen();
healthClient = new health.Client('localhost:' + port_num);
});
after(function() {
healthServer.shutdown();
});
it('should say an enabled service is SERVING', function(done) {
healthClient.check({service: ''}, function(err, response) {
assert.ifError(err);
assert.strictEqual(response.status, 'SERVING');
done();
});
});
it('should say that a disabled service is NOT_SERVING', function(done) {
healthClient.check({service: 'grpc.test.TestService'},
function(err, response) {
assert.ifError(err);
assert.strictEqual(response.status, 'NOT_SERVING');
done();
});
});
it('should say that a service on another host is SERVING', function(done) {
healthClient.check({host: 'virtual_host', service: 'grpc.test.TestService'},
function(err, response) {
assert.ifError(err);
assert.strictEqual(response.status, 'SERVING');
done();
});
});
it('should get NOT_FOUND if the service is not registered', function(done) {
healthClient.check({service: 'not_registered'}, function(err, response) {
assert(err);
assert.strictEqual(err.code, grpc.status.NOT_FOUND);
done();
});
});
it('should get NOT_FOUND if the host is not registered', function(done) {
healthClient.check({host: 'wrong_host', service: 'grpc.test.TestService'},
function(err, response) {
assert(err);
assert.strictEqual(err.code, grpc.status.NOT_FOUND);
done();
});
});
});
enum34==1.0.4 enum34==1.0.4
futures==2.2.0 futures==2.2.0
protobuf==3.0.0a3 protobuf==3.0.0a3
cython>=0.22
MANIFEST MANIFEST
grpcio.egg-info/ grpcio.egg-info/
build/
dist/ dist/
*.a
*.so
*.dll
*.pyc
*.pyd
*.h
*.c
*.a
*.so
*.dll
*.pyc
*.pyd
GRPC Python Cython layer
========================
Package for the GRPC Python Cython layer.
What is Cython?
---------------
Cython is both a superset of the Python language with extensions for dealing
with C types and a tool that transpiles this superset into C code. It provides
convenient means of statically typing expressions and of converting Python
strings to pointers (among other niceties), thus dramatically smoothing the
Python/C interop by allowing fluid use of APIs in both from the same source.
See the wonderful `Cython website`_.
Why Cython?
-----------
- **Python 2 and 3 support**
Cython generated C code has precompiler macros to target both Python 2 and
Python 3 C APIs, even while acting as a superset of just the Python 2
language (e.g. using ``basestring``).
- **Significantly less semantic noise**
A lot of CPython code is just glue, especially human-error-prone
``Py_INCREF``-ing and ``Py_DECREF``-ing around error handlers and such.
Cython takes care of that automagically.
- **Possible PyPy support**
One of the major developments in Cython over the past few years was the
addition of support for PyPy. We might soon be able to provide such support
ourselves through our use of Cython.
- **Less Python glue code**
There existed several adapter layers in and around the original CPython code
to smooth the surface exposed to Python due to how much trouble it was to
make such a smooth surface via the CPython API alone. Cython makes writing
such a surface incredibly easy, so these adapter layers may be removed.
Implications for Users
----------------------
Nothing additional will be required for users. PyPI packages will contain
Cython generated C code and thus not necessitate a Cython installation.
Implications for GRPC Developers
--------------------------------
A typical edit-compile-debug cycle now requires Cython. We install Cython in
the ``virtualenv`` generated for the Python tests in this repository, so
initial test runs may take an extra 2+ minutes to complete. Subsequent test
runs won't reinstall ``Cython`` (unless required versions change and the
``virtualenv`` doesn't have installed versions that satisfy the change).
.. _`Cython website`: http://cython.org/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment