Skip to content

Commit 9dd8f1a

Browse files
Created the ConfigManager interface (istio#338)
* Created the ConfigManager interface * Added ConfigManagerImpl * Removed ConfigManager interface and rename the ConfigManagerImp to ConfigManager. * Applied code reviews * Created the service_management_fetch library * Removed unimplemented method definition * Moved ServiceManagement related code to the library * Created ServiceManagementFetch class * Removed unnecessary headers inclusion, fixed typo, used std::move * Used lvalue reference for std::move * Removed const definition * Renamed variables and method names * Removed console debugging codes * Made service config fetch in parallel. Changed constructor of ConfigsFetchInfo * Changed the callback prototype in test cases * Moved config_id and percentage variables to lambda capture * Added missing proto files
1 parent 729519e commit 9dd8f1a

9 files changed

+1430
-0
lines changed

contrib/endpoints/repositories.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,12 @@ cc_proto_library(
242242
"google/api/servicecontrol/v1/metric_value.proto",
243243
"google/api/servicecontrol/v1/operation.proto",
244244
"google/api/servicecontrol/v1/service_controller.proto",
245+
"google/api/servicemanagement/v1/servicemanager.proto",
246+
"google/api/servicemanagement/v1/resources.proto",
245247
"google/logging/type/http_request.proto",
246248
"google/logging/type/log_severity.proto",
249+
"google/api/config_change.proto",
250+
"google/longrunning/operations.proto",
247251
"google/rpc/error_details.proto",
248252
"google/rpc/status.proto",
249253
"google/type/money.proto",

contrib/endpoints/src/api_manager/BUILD

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ cc_library(
8585
"check_workflow.cc",
8686
"check_workflow.h",
8787
"config.cc",
88+
"config_manager.cc",
89+
"config_manager.h",
8890
"fetch_metadata.cc",
8991
"fetch_metadata.h",
9092
"gce_metadata.cc",
@@ -93,6 +95,8 @@ cc_library(
9395
"quota_control.cc",
9496
"quota_control.h",
9597
"request_handler.cc",
98+
"service_management_fetch.cc",
99+
"service_management_fetch.h",
96100
"weighted_selector.cc",
97101
"weighted_selector.h",
98102
],
@@ -201,6 +205,36 @@ cc_test(
201205
],
202206
)
203207

208+
cc_test(
209+
name = "config_manager_test",
210+
size = "small",
211+
srcs = [
212+
"config_manager_test.cc",
213+
"mock_request.h",
214+
],
215+
linkstatic = 1,
216+
deps = [
217+
":api_manager",
218+
":mock_api_manager_environment",
219+
"//external:googletest_main",
220+
],
221+
)
222+
223+
cc_test(
224+
name = "service_management_fetch_test",
225+
size = "small",
226+
srcs = [
227+
"mock_request.h",
228+
"service_management_fetch_test.cc",
229+
],
230+
linkstatic = 1,
231+
deps = [
232+
":api_manager",
233+
":mock_api_manager_environment",
234+
"//external:googletest_main",
235+
],
236+
)
237+
204238
cc_test(
205239
name = "http_template_test",
206240
size = "small",

contrib/endpoints/src/api_manager/auth/service_account_token.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class ServiceAccountToken {
6969
// JWT token for accessing the http endpoints defined in Firebase Rules.
7070
JWT_TOKEN_FOR_AUTHORIZATION_SERVICE,
7171
JWT_TOKEN_FOR_QUOTA_CONTROL,
72+
JWT_TOKEN_FOR_SERVICEMANAGEMENT_SERVICES,
7273
JWT_TOKEN_TYPE_MAX,
7374
};
7475
// Set audience. Only calcualtes JWT token with specified audience.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/* Copyright 2017 Google Inc. All Rights Reserved.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
#include "contrib/endpoints/src/api_manager/config_manager.h"
16+
#include "contrib/endpoints/src/api_manager/fetch_metadata.h"
17+
18+
namespace google {
19+
namespace api_manager {
20+
21+
namespace {
22+
// Default rollouts refresh interval in ms
23+
const int kCheckNewRolloutInterval = 60000;
24+
25+
// static configs for error handling
26+
static std::vector<std::pair<std::string, int>> kEmptyConfigs;
27+
} // namespace anonymous
28+
29+
ConfigManager::ConfigManager(
30+
std::shared_ptr<context::GlobalContext> global_context,
31+
RolloutApplyFunction rollout_apply_function)
32+
: global_context_(global_context),
33+
rollout_apply_function_(rollout_apply_function),
34+
refresh_interval_ms_(kCheckNewRolloutInterval) {
35+
if (global_context_->server_config()->has_service_management_config()) {
36+
// update refresh interval in ms
37+
if (global_context_->server_config()
38+
->service_management_config()
39+
.refresh_interval_ms() > 0) {
40+
refresh_interval_ms_ = global_context_->server_config()
41+
->service_management_config()
42+
.refresh_interval_ms();
43+
}
44+
}
45+
46+
service_management_fetch_.reset(new ServiceManagementFetch(global_context));
47+
}
48+
49+
void ConfigManager::Init() {
50+
if (global_context_->service_name().empty() ||
51+
global_context_->config_id().empty()) {
52+
GlobalFetchGceMetadata(global_context_, [this](utils::Status status) {
53+
OnFetchMetadataDone(status);
54+
});
55+
} else {
56+
OnFetchMetadataDone(utils::Status::OK);
57+
}
58+
}
59+
60+
void ConfigManager::OnFetchMetadataDone(utils::Status status) {
61+
if (!status.ok()) {
62+
// We should not get here
63+
global_context_->env()->LogError("Unexpected status: " + status.ToString());
64+
rollout_apply_function_(utils::Status(Code::ABORTED, status.ToString()),
65+
kEmptyConfigs);
66+
return;
67+
}
68+
69+
// Update service_name
70+
if (global_context_->service_name().empty()) {
71+
global_context_->set_service_name(
72+
global_context_->gce_metadata()->endpoints_service_name());
73+
}
74+
75+
// Update config_id
76+
if (global_context_->config_id().empty()) {
77+
global_context_->config_id(
78+
global_context_->gce_metadata()->endpoints_service_config_id());
79+
}
80+
81+
// Call ApiManager with status Code::ABORTED, ESP will stop moving forward
82+
if (global_context_->service_name().empty()) {
83+
std::string msg = "API service name is not specified";
84+
global_context_->env()->LogError(msg);
85+
rollout_apply_function_(utils::Status(Code::ABORTED, msg), kEmptyConfigs);
86+
return;
87+
}
88+
89+
// TODO(jaebong) config_id should not be empty for the first version
90+
// This part will be removed after the rollouts feature added
91+
if (global_context_->config_id().empty()) {
92+
std::string msg = "API config_id is not specified";
93+
global_context_->env()->LogError(msg);
94+
rollout_apply_function_(utils::Status(Code::ABORTED, msg), kEmptyConfigs);
95+
return;
96+
}
97+
98+
// Fetch service account token
99+
GlobalFetchServiceAccountToken(global_context_, [this](utils::Status status) {
100+
OnFetchAuthTokenDone(status);
101+
});
102+
}
103+
104+
void ConfigManager::OnFetchAuthTokenDone(utils::Status status) {
105+
if (!status.ok()) {
106+
// We should not get here
107+
global_context_->env()->LogError("Unexpected status: " + status.ToString());
108+
rollout_apply_function_(utils::Status(Code::ABORTED, status.ToString()),
109+
kEmptyConfigs);
110+
return;
111+
}
112+
113+
// Fetch configs from the Inception
114+
// For now, config manager has only one config_id (100% rollout)
115+
std::shared_ptr<ConfigsFetchInfo> config_fetch_info(
116+
new ConfigsFetchInfo({{global_context_->config_id(), 100}}));
117+
118+
FetchConfigs(config_fetch_info);
119+
}
120+
121+
// Fetch configs from rollouts. fetch_info has rollouts and fetched configs
122+
void ConfigManager::FetchConfigs(
123+
std::shared_ptr<ConfigsFetchInfo> config_fetch_info) {
124+
for (auto rollout : config_fetch_info->rollouts) {
125+
std::string config_id = rollout.first;
126+
int percentage = rollout.second;
127+
service_management_fetch_->GetConfig(config_id, [this, config_id,
128+
percentage,
129+
config_fetch_info](
130+
const utils::Status&
131+
status,
132+
std::string&& config) {
133+
134+
if (status.ok()) {
135+
config_fetch_info->configs.push_back({std::move(config), percentage});
136+
} else {
137+
global_context_->env()->LogError(std::string(
138+
"Unable to download Service config for the config_id: " +
139+
config_id));
140+
}
141+
142+
config_fetch_info->finished++;
143+
144+
if (config_fetch_info->IsCompleted()) {
145+
// Failed to fetch all configs or rollouts are empty
146+
if (config_fetch_info->IsRolloutsEmpty() ||
147+
config_fetch_info->IsConfigsEmpty()) {
148+
// first time, call the ApiManager callback function with an error
149+
rollout_apply_function_(
150+
utils::Status(Code::ABORTED,
151+
"Failed to download the service config"),
152+
kEmptyConfigs);
153+
return;
154+
}
155+
156+
// Update ApiManager
157+
rollout_apply_function_(utils::Status::OK, config_fetch_info->configs);
158+
}
159+
});
160+
}
161+
}
162+
163+
} // namespace api_manager
164+
} // namespace google
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* Copyright 2017 Google Inc. All Rights Reserved.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
#ifndef API_MANAGER_CONFIG_MANAGER_H_
16+
#define API_MANAGER_CONFIG_MANAGER_H_
17+
18+
#include "contrib/endpoints/src/api_manager/context/global_context.h"
19+
#include "contrib/endpoints/src/api_manager/service_management_fetch.h"
20+
21+
namespace google {
22+
namespace api_manager {
23+
24+
namespace {
25+
26+
// RolloutApplyFunction is the callback provided by ApiManager.
27+
// ConfigManager calls the callback after the service config download
28+
//
29+
// status
30+
// - Code::OK Config manager was successfully initialized
31+
// - Code::ABORTED Fatal error
32+
// - Code::UNKNOWN Config manager was not initialized yet
33+
// configs - pairs of ServiceConfig in text and rollout percentages
34+
typedef std::function<void(
35+
const utils::Status& status,
36+
const std::vector<std::pair<std::string, int>>& configs)>
37+
RolloutApplyFunction;
38+
39+
// Data structure to fetch configs from rollouts
40+
struct ConfigsFetchInfo {
41+
ConfigsFetchInfo() : finished(0) {}
42+
43+
ConfigsFetchInfo(std::vector<std::pair<std::string, int>>&& rollouts)
44+
: rollouts(std::move(rollouts)), finished(0) {}
45+
46+
// config_ids to be fetched and rollouts percentages
47+
std::vector<std::pair<std::string, int>> rollouts;
48+
// fetched ServiceConfig and rollouts percentages
49+
std::vector<std::pair<std::string, int>> configs;
50+
// Finished fetching
51+
inline bool IsCompleted() { return ((size_t)finished == rollouts.size()); }
52+
// Check fetched rollout is empty
53+
inline bool IsRolloutsEmpty() { return rollouts.empty(); }
54+
// Check fetched configs are empty
55+
inline bool IsConfigsEmpty() { return configs.empty(); }
56+
57+
// Finished service config fetch count
58+
int finished;
59+
};
60+
61+
} // namespace anonymous
62+
63+
// Manages configuration downloading
64+
class ConfigManager {
65+
public:
66+
ConfigManager(std::shared_ptr<context::GlobalContext> global_context,
67+
RolloutApplyFunction config_rollout_callback);
68+
virtual ~ConfigManager(){};
69+
70+
public:
71+
// Initialize the instance
72+
void Init();
73+
74+
private:
75+
// Fetch ServiceConfig details from the latest successful rollouts
76+
// https://goo.gl/I2nD4M
77+
void FetchConfigs(std::shared_ptr<ConfigsFetchInfo> config_fetch_info);
78+
// Handle metadata fetch done
79+
void OnFetchMetadataDone(utils::Status status);
80+
// Handle auth token fetch done
81+
void OnFetchAuthTokenDone(utils::Status status);
82+
83+
// Global context provided by ApiManager
84+
std::shared_ptr<context::GlobalContext> global_context_;
85+
// ApiManager updated callback
86+
RolloutApplyFunction rollout_apply_function_;
87+
// Rollouts refresh check interval in ms
88+
int refresh_interval_ms_;
89+
// ServiceManagement service client instance
90+
std::unique_ptr<ServiceManagementFetch> service_management_fetch_;
91+
};
92+
93+
} // namespace api_manager
94+
} // namespace google
95+
#endif // API_MANAGER_CONFIG_MANAGER_H_

0 commit comments

Comments
 (0)