@google-cloud/nodejs-common 0.9.2-beta → 0.9.2-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/install_functions.sh +85 -240
- package/package.json +1 -1
- package/src/apis/analytics.js +17 -9
- package/src/apis/auth_client.js +3 -1
- package/src/apis/measurement_protocol.js +32 -19
- package/src/components/utils.js +13 -1
package/bin/install_functions.sh
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# limitations under the License.
|
|
16
16
|
|
|
17
17
|
# Cloud Functions Runtime Environment.
|
|
18
|
-
CF_RUNTIME="${CF_RUNTIME:=
|
|
18
|
+
CF_RUNTIME="${CF_RUNTIME:=nodejs10}"
|
|
19
19
|
|
|
20
20
|
# Counter for steps.
|
|
21
21
|
STEP=0
|
|
@@ -138,14 +138,6 @@ EXTERNAL_API_SCOPES=(
|
|
|
138
138
|
# Enabled APIs' OAuth scopes.
|
|
139
139
|
ENABLED_OAUTH_SCOPES=()
|
|
140
140
|
|
|
141
|
-
# No explicit service account is required.
|
|
142
|
-
# https://cloud.google.com/iam/docs/understanding-roles#service-accounts-roles
|
|
143
|
-
#declare -A GOOGLE_SERVICE_ACCOUNT_PERMISSIONS
|
|
144
|
-
#GOOGLE_SERVICE_ACCOUNT_PERMISSIONS=(
|
|
145
|
-
# ["Service Account Admin"]="iam.serviceAccounts.create"
|
|
146
|
-
# ["Service Account Key Admin"]="iam.serviceAccounts.create"
|
|
147
|
-
#)
|
|
148
|
-
|
|
149
141
|
# Preparation functions.
|
|
150
142
|
#######################################
|
|
151
143
|
# Mimic a Cloud Shell environment to enable local running.
|
|
@@ -590,11 +582,6 @@ authentication method:"
|
|
|
590
582
|
printf '%s\n' "... OAuth is selected."
|
|
591
583
|
else
|
|
592
584
|
NEED_SERVICE_ACCOUNT="true"
|
|
593
|
-
# local role
|
|
594
|
-
# for role in "${!GOOGLE_SERVICE_ACCOUNT_PERMISSIONS[@]}"; do
|
|
595
|
-
# GOOGLE_CLOUD_PERMISSIONS["${role}"]=\
|
|
596
|
-
#"${GOOGLE_SERVICE_ACCOUNT_PERMISSIONS["${role}"]}"
|
|
597
|
-
# done
|
|
598
585
|
printf '%s\n' "... Service Account is selected."
|
|
599
586
|
fi
|
|
600
587
|
}
|
|
@@ -1192,6 +1179,87 @@ EOF
|
|
|
1192
1179
|
printf '%s\n' "OK. Continue with monitored folder [${folder}]."
|
|
1193
1180
|
}
|
|
1194
1181
|
|
|
1182
|
+
#######################################
|
|
1183
|
+
# Create or update a Log router sink.
|
|
1184
|
+
# Globals:
|
|
1185
|
+
# None
|
|
1186
|
+
# Arguments:
|
|
1187
|
+
# Name of the sink
|
|
1188
|
+
# Filter conditions
|
|
1189
|
+
# Sink destination
|
|
1190
|
+
#######################################
|
|
1191
|
+
create_or_update_sink() {
|
|
1192
|
+
local sinkName=${1}
|
|
1193
|
+
local logFilter=${2}
|
|
1194
|
+
local sinkDestAndFlags=(${3})
|
|
1195
|
+
local existingFilter
|
|
1196
|
+
existingFilter=$(gcloud logging sinks list --filter="name:${sinkName}" \
|
|
1197
|
+
--format="value(filter)")
|
|
1198
|
+
if [[ "${existingFilter}" != "${logFilter}" ]]; then
|
|
1199
|
+
local action
|
|
1200
|
+
if [[ -z "${existingFilter}" ]]; then
|
|
1201
|
+
action="create"
|
|
1202
|
+
printf '%s\n' " Logging Export [${sinkName}] doesn't exist. Creating..."
|
|
1203
|
+
else
|
|
1204
|
+
action="update"
|
|
1205
|
+
printf '%s\n' " Logging Export [${sinkName}] exists with a different \
|
|
1206
|
+
filter. Updating..."
|
|
1207
|
+
fi
|
|
1208
|
+
gcloud -q logging sinks ${action} "${sinkName}" "${sinkDestAndFlags[@]}" \
|
|
1209
|
+
--log-filter="${logFilter}"
|
|
1210
|
+
else
|
|
1211
|
+
printf '%s\n' " Logging Export [${sinkName}] exists. Continue..."
|
|
1212
|
+
fi
|
|
1213
|
+
if [[ $? -gt 0 ]];then
|
|
1214
|
+
printf '%s\n' "Failed to create or update Logs router sink."
|
|
1215
|
+
return 1
|
|
1216
|
+
fi
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
#######################################
|
|
1220
|
+
# Confirm the service account of the given sink has proper permission to dump
|
|
1221
|
+
# the logs.
|
|
1222
|
+
# Globals:
|
|
1223
|
+
# None
|
|
1224
|
+
# Arguments:
|
|
1225
|
+
# Name of the sink
|
|
1226
|
+
# Bindings role, e.g. "pubsub.publisher" or "bigquery.dataEditor"
|
|
1227
|
+
# Role name, e.g. "Pub/Sub Publisher" or "BigQuery Data Editor"
|
|
1228
|
+
#######################################
|
|
1229
|
+
confirm_sink_service_account_permission() {
|
|
1230
|
+
local sinkName=${1}
|
|
1231
|
+
local bindingsRole=${2}
|
|
1232
|
+
local roleName=${3}
|
|
1233
|
+
local serviceAccount existingRole
|
|
1234
|
+
serviceAccount=$(gcloud logging sinks describe "${sinkName}" \
|
|
1235
|
+
--format="get(writerIdentity)")
|
|
1236
|
+
while :;do
|
|
1237
|
+
printf '%s\n' " Checking the role of the sink's service account \
|
|
1238
|
+
[${serviceAccount}]..."
|
|
1239
|
+
existingRole=$(gcloud projects get-iam-policy "${GCP_PROJECT}" \
|
|
1240
|
+
--flatten=bindings --filter="bindings.members:${serviceAccount} AND \
|
|
1241
|
+
bindings.role:roles/${bindingsRole}" --format="get(bindings.members)")
|
|
1242
|
+
if [[ -z "${existingRole}" ]];then
|
|
1243
|
+
printf '%s\n' " Granting Role '${roleName}' to the service \
|
|
1244
|
+
account..."
|
|
1245
|
+
gcloud -q projects add-iam-policy-binding "${GCP_PROJECT}" --member \
|
|
1246
|
+
"${serviceAccount}" --role roles/${bindingsRole}
|
|
1247
|
+
if [[ $? -gt 0 ]];then
|
|
1248
|
+
printf '%s\n' "Failed to grant the role. Use this link \
|
|
1249
|
+
https://console.cloud.google.com/iam-admin/iam?project=${GCP_PROJECT} to \
|
|
1250
|
+
manually grant Role '${roleName}' to ${serviceAccount}."
|
|
1251
|
+
printf '%s' "Press any key to continue after you grant the access..."
|
|
1252
|
+
local any
|
|
1253
|
+
read -n1 -s any
|
|
1254
|
+
continue
|
|
1255
|
+
fi
|
|
1256
|
+
else
|
|
1257
|
+
printf '%s\n' " The role has already been granted."
|
|
1258
|
+
return 0
|
|
1259
|
+
fi
|
|
1260
|
+
done
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1195
1263
|
#######################################
|
|
1196
1264
|
# Save the configuration to a local file.
|
|
1197
1265
|
# Globals:
|
|
@@ -1232,7 +1300,9 @@ save_config() {
|
|
|
1232
1300
|
# For service account, given that Cloud Functions can extend the authorized API
|
|
1233
1301
|
# scopes now, it will use the default service account rather than an explicit
|
|
1234
1302
|
# service account with the key file downloaded. By doing so, we can reduce the
|
|
1235
|
-
# risk of leaking service account key.
|
|
1303
|
+
# risk of leaking service account key. If there is a service key in the current
|
|
1304
|
+
# folder from previous installation, the code will continue using it, otherwise
|
|
1305
|
+
# it will use the Cloud Functions' default service account.
|
|
1236
1306
|
# For OAuth 2.0, guide user to complete OAuth authentication and save the
|
|
1237
1307
|
# refresh token.
|
|
1238
1308
|
# Globals:
|
|
@@ -1242,155 +1312,11 @@ save_config() {
|
|
|
1242
1312
|
# None
|
|
1243
1313
|
#######################################
|
|
1244
1314
|
do_authentication(){
|
|
1245
|
-
# If there is a service key in the current folder from previous installation,
|
|
1246
|
-
# the code will continue using it, otherwise it will use the Cloud Functions'
|
|
1247
|
-
# default service account.
|
|
1248
|
-
# if [[ ${NEED_SERVICE_ACCOUNT} == "true" ]]; then
|
|
1249
|
-
# download_service_account_key
|
|
1250
|
-
# fi
|
|
1251
1315
|
if [[ ${NEED_OAUTH} == "true" ]]; then
|
|
1252
1316
|
do_oauth
|
|
1253
1317
|
fi
|
|
1254
1318
|
}
|
|
1255
1319
|
|
|
1256
|
-
#######################################
|
|
1257
|
-
# Download a service account key file and save as `$SA_KEY_FILE`.
|
|
1258
|
-
# Globals:
|
|
1259
|
-
# SA_NAME
|
|
1260
|
-
# GCP_PROJECT
|
|
1261
|
-
# SA_KEY_FILE
|
|
1262
|
-
# Arguments:
|
|
1263
|
-
# None
|
|
1264
|
-
# Returns:
|
|
1265
|
-
# 0 if service key files exists or created, non-zero on error.
|
|
1266
|
-
#######################################
|
|
1267
|
-
download_service_account_key() {
|
|
1268
|
-
(( STEP += 1 ))
|
|
1269
|
-
printf '%s\n' "Step ${STEP}: Downloading the key file for the service \
|
|
1270
|
-
account..."
|
|
1271
|
-
if [[ -z ${SA_NAME} ]];then
|
|
1272
|
-
confirm_service_account
|
|
1273
|
-
fi
|
|
1274
|
-
local suffix exist
|
|
1275
|
-
suffix=$(get_sa_domain_from_gcp_id "${GCP_PROJECT}")
|
|
1276
|
-
local email="${SA_NAME}@${suffix}"
|
|
1277
|
-
local prompt="Would you like to download the key file for [${email}] and \
|
|
1278
|
-
save it as ${SA_KEY_FILE}? [Y/n]: "
|
|
1279
|
-
local default_value="y"
|
|
1280
|
-
if [[ -f "${SA_KEY_FILE}" && -s "${SA_KEY_FILE}" ]]; then
|
|
1281
|
-
exist=$(get_value_from_json_file ${SA_KEY_FILE} 'client_email' 2>&1)
|
|
1282
|
-
if [[ ${exist} =~ .*("@${suffix}") ]]; then
|
|
1283
|
-
prompt="A key file for [${exist}] with the key ID '\
|
|
1284
|
-
$(get_value_from_json_file ${SA_KEY_FILE} 'private_key_id') already exists'. \
|
|
1285
|
-
Would you like to create a new key to overwrite it? [N/y]: "
|
|
1286
|
-
default_value="n"
|
|
1287
|
-
fi
|
|
1288
|
-
fi
|
|
1289
|
-
printf '%s' "${prompt}"
|
|
1290
|
-
local input
|
|
1291
|
-
read -r input
|
|
1292
|
-
input=${input:-"${default_value}"}
|
|
1293
|
-
if [[ ${input} == 'y' || ${input} == 'Y' ]];then
|
|
1294
|
-
printf '%s\n' "Downloading a new key file for [${email}]..."
|
|
1295
|
-
gcloud iam service-accounts keys create "${SA_KEY_FILE}" --iam-account \
|
|
1296
|
-
"${email}"
|
|
1297
|
-
if [[ $? -gt 0 ]]; then
|
|
1298
|
-
printf '%s\n' "Failed to download new key files for [${email}]."
|
|
1299
|
-
return 1
|
|
1300
|
-
else
|
|
1301
|
-
printf '%s\n' "OK. New key file is saved at [${SA_KEY_FILE}]."
|
|
1302
|
-
return 0
|
|
1303
|
-
fi
|
|
1304
|
-
else
|
|
1305
|
-
printf '%s\n' "Skipped downloading new key file. See \
|
|
1306
|
-
https://cloud.google.com/iam/docs/creating-managing-service-account-keys \
|
|
1307
|
-
to learn more about service account key files."
|
|
1308
|
-
return 0
|
|
1309
|
-
fi
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
#######################################
|
|
1313
|
-
# Make sure a service account for this integration exists and set the email of
|
|
1314
|
-
# the service account to the global variable `SA_NAME`.
|
|
1315
|
-
# Globals:
|
|
1316
|
-
# GCP_PROJECT
|
|
1317
|
-
# SA_KEY_FILE
|
|
1318
|
-
# SA_NAME
|
|
1319
|
-
# DEFAULT_SERVICE_ACCOUNT
|
|
1320
|
-
# Arguments:
|
|
1321
|
-
# None
|
|
1322
|
-
#######################################
|
|
1323
|
-
confirm_service_account() {
|
|
1324
|
-
cat <<EOF
|
|
1325
|
-
Some external APIs might require authentication based on OAuth or \
|
|
1326
|
-
JWT(service account), for example, Google Analytics or Campaign Manager. \
|
|
1327
|
-
In this step, you prepare the service account. For more information, see \
|
|
1328
|
-
https://cloud.google.com/iam/docs/creating-managing-service-accounts
|
|
1329
|
-
EOF
|
|
1330
|
-
|
|
1331
|
-
local suffix
|
|
1332
|
-
suffix=$(get_sa_domain_from_gcp_id "${GCP_PROJECT}")
|
|
1333
|
-
local email
|
|
1334
|
-
if [[ -f "${SA_KEY_FILE}" && -s "${SA_KEY_FILE}" ]]; then
|
|
1335
|
-
email=$(get_value_from_json_file "${SA_KEY_FILE}" 'client_email')
|
|
1336
|
-
if [[ ${email} =~ .*("@${suffix}") ]]; then
|
|
1337
|
-
printf '%s' "A key file for service account [${email}] already exists. \
|
|
1338
|
-
Would you like to create a new service account? [N/y]: "
|
|
1339
|
-
local input
|
|
1340
|
-
read -r input
|
|
1341
|
-
if [[ ${input} != 'y' && ${input} != 'Y' ]]; then
|
|
1342
|
-
printf '%s\n' "OK. Will use existing service account [${email}]."
|
|
1343
|
-
SA_NAME=$(printf "${email}" | cut -d@ -f1)
|
|
1344
|
-
return 0
|
|
1345
|
-
fi
|
|
1346
|
-
fi
|
|
1347
|
-
fi
|
|
1348
|
-
|
|
1349
|
-
SA_NAME="${SA_NAME:-"${PROJECT_NAMESPACE}-api"}"
|
|
1350
|
-
while :; do
|
|
1351
|
-
printf '%s' "Enter the name of service account [${SA_NAME}]: "
|
|
1352
|
-
local input sa_elements=() sa
|
|
1353
|
-
read -r input
|
|
1354
|
-
input=${input:-"${SA_NAME}"}
|
|
1355
|
-
IFS='@' read -a sa_elements <<< "${input}"
|
|
1356
|
-
if [[ ${#sa_elements[@]} == 1 ]]; then
|
|
1357
|
-
echo " Append default suffix to service account name and get: ${email}"
|
|
1358
|
-
sa="${input}"
|
|
1359
|
-
email="${sa}@${suffix}"
|
|
1360
|
-
else
|
|
1361
|
-
if [[ ${sa_elements[1]} != "${suffix}" ]]; then
|
|
1362
|
-
printf '%s\n' " Error: Service account domain name ${sa_elements[1]} \
|
|
1363
|
-
doesn't belong to the current project. The service account domain name for the \
|
|
1364
|
-
current project should be: ${suffix}."
|
|
1365
|
-
continue
|
|
1366
|
-
fi
|
|
1367
|
-
sa="${sa_elements[0]}"
|
|
1368
|
-
email="${input}"
|
|
1369
|
-
fi
|
|
1370
|
-
|
|
1371
|
-
printf '%s\n' "Checking the existence of the service account [${email}]..."
|
|
1372
|
-
if ! result=$(gcloud iam service-accounts describe "${email}" 2>&1); then
|
|
1373
|
-
printf '%s\n' " Service account [${email}] does not exist. Trying to \
|
|
1374
|
-
create..."
|
|
1375
|
-
gcloud iam service-accounts create "${sa}" --display-name \
|
|
1376
|
-
"Tentacles API requester"
|
|
1377
|
-
if [[ $? -gt 0 ]]; then
|
|
1378
|
-
printf '%s\n' "Creating the service account [${email}] failed. Please \
|
|
1379
|
-
try again..."
|
|
1380
|
-
else
|
|
1381
|
-
printf '%s\n' "The service account [${email}] was successfully created."
|
|
1382
|
-
SA_NAME=${sa}
|
|
1383
|
-
break
|
|
1384
|
-
fi
|
|
1385
|
-
else
|
|
1386
|
-
printf ' found.\n'
|
|
1387
|
-
SA_NAME=${sa}
|
|
1388
|
-
break
|
|
1389
|
-
fi
|
|
1390
|
-
done
|
|
1391
|
-
printf '%s\n' "OK. Service account [${SA_NAME}] is ready."
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
1320
|
#######################################
|
|
1395
1321
|
# Guide an OAuth process and save the token to file.
|
|
1396
1322
|
# The whole process will be:
|
|
@@ -1517,87 +1443,6 @@ EOF
|
|
|
1517
1443
|
done
|
|
1518
1444
|
}
|
|
1519
1445
|
|
|
1520
|
-
#######################################
|
|
1521
|
-
# Create or update a Log router sink.
|
|
1522
|
-
# Globals:
|
|
1523
|
-
# None
|
|
1524
|
-
# Arguments:
|
|
1525
|
-
# Name of the sink
|
|
1526
|
-
# Filter conditions
|
|
1527
|
-
# Sink destination
|
|
1528
|
-
#######################################
|
|
1529
|
-
create_or_update_sink() {
|
|
1530
|
-
local sinkName=${1}
|
|
1531
|
-
local logFilter=${2}
|
|
1532
|
-
local sinkDestAndFlags=(${3})
|
|
1533
|
-
local existingFilter
|
|
1534
|
-
existingFilter=$(gcloud logging sinks list --filter="name:${sinkName}" \
|
|
1535
|
-
--format="value(filter)")
|
|
1536
|
-
if [[ "${existingFilter}" != "${logFilter}" ]]; then
|
|
1537
|
-
local action
|
|
1538
|
-
if [[ -z "${existingFilter}" ]]; then
|
|
1539
|
-
action="create"
|
|
1540
|
-
printf '%s\n' " Logging Export [${sinkName}] doesn't exist. Creating..."
|
|
1541
|
-
else
|
|
1542
|
-
action="update"
|
|
1543
|
-
printf '%s\n' " Logging Export [${sinkName}] exists with a different \
|
|
1544
|
-
filter. Updating..."
|
|
1545
|
-
fi
|
|
1546
|
-
gcloud -q logging sinks ${action} "${sinkName}" "${sinkDestAndFlags[@]}" \
|
|
1547
|
-
--log-filter="${logFilter}"
|
|
1548
|
-
else
|
|
1549
|
-
printf '%s\n' " Logging Export [${sinkName}] exists. Continue..."
|
|
1550
|
-
fi
|
|
1551
|
-
if [[ $? -gt 0 ]];then
|
|
1552
|
-
printf '%s\n' "Failed to create or update Logs router sink."
|
|
1553
|
-
return 1
|
|
1554
|
-
fi
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
#######################################
|
|
1558
|
-
# Confirm the service account of the given sink has proper permission to dump
|
|
1559
|
-
# the logs.
|
|
1560
|
-
# Globals:
|
|
1561
|
-
# None
|
|
1562
|
-
# Arguments:
|
|
1563
|
-
# Name of the sink
|
|
1564
|
-
# Bindings role, e.g. "pubsub.publisher" or "bigquery.dataEditor"
|
|
1565
|
-
# Role name, e.g. "Pub/Sub Publisher" or "BigQuery Data Editor"
|
|
1566
|
-
#######################################
|
|
1567
|
-
confirm_sink_service_account_permission() {
|
|
1568
|
-
local sinkName=${1}
|
|
1569
|
-
local bindingsRole=${2}
|
|
1570
|
-
local roleName=${3}
|
|
1571
|
-
local serviceAccount existingRole
|
|
1572
|
-
serviceAccount=$(gcloud logging sinks describe "${sinkName}" \
|
|
1573
|
-
--format="get(writerIdentity)")
|
|
1574
|
-
while :;do
|
|
1575
|
-
printf '%s\n' " Checking the role of the sink's service account \
|
|
1576
|
-
[${serviceAccount}]..."
|
|
1577
|
-
existingRole=$(gcloud projects get-iam-policy "${GCP_PROJECT}" \
|
|
1578
|
-
--flatten=bindings --filter="bindings.members:${serviceAccount} AND \
|
|
1579
|
-
bindings.role:roles/${bindingsRole}" --format="get(bindings.members)")
|
|
1580
|
-
if [[ -z "${existingRole}" ]];then
|
|
1581
|
-
printf '%s\n' " Granting Role '${roleName}' to the service \
|
|
1582
|
-
account..."
|
|
1583
|
-
gcloud -q projects add-iam-policy-binding "${GCP_PROJECT}" --member \
|
|
1584
|
-
"${serviceAccount}" --role roles/bigquery.dataEditor
|
|
1585
|
-
if [[ $? -gt 0 ]];then
|
|
1586
|
-
printf '%s\n' "Failed to grant the role. Use this link \
|
|
1587
|
-
https://console.cloud.google.com/iam-admin/iam?project=${GCP_PROJECT} to \
|
|
1588
|
-
manually grant Role '${roleName}' to ${serviceAccount}."
|
|
1589
|
-
printf '%s' "Press any key to continue after you grant the access..."
|
|
1590
|
-
local any
|
|
1591
|
-
read -n1 -s any
|
|
1592
|
-
continue
|
|
1593
|
-
fi
|
|
1594
|
-
else
|
|
1595
|
-
printf '%s\n' " The role has already been granted."
|
|
1596
|
-
return 0
|
|
1597
|
-
fi
|
|
1598
|
-
done
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
1446
|
#######################################
|
|
1602
1447
|
# Set default configuration for a Cloud Functions.
|
|
1603
1448
|
# Globals:
|
package/package.json
CHANGED
package/src/apis/analytics.js
CHANGED
|
@@ -23,7 +23,7 @@ const stream = require('stream');
|
|
|
23
23
|
const {google} = require('googleapis');
|
|
24
24
|
const {Schema$Upload} = google.analytics;
|
|
25
25
|
const AuthClient = require('./auth_client.js');
|
|
26
|
-
const {wait, getLogger} = require('../components/utils.js');
|
|
26
|
+
const {wait, getLogger, BatchResult} = require('../components/utils.js');
|
|
27
27
|
|
|
28
28
|
const API_SCOPES = Object.freeze([
|
|
29
29
|
'https://www.googleapis.com/auth/analytics',
|
|
@@ -81,8 +81,7 @@ class Analytics {
|
|
|
81
81
|
* @param {string|!stream.Readable} data A string or a stream to be uploaded.
|
|
82
82
|
* @param {!DataImportConfig} config GA data import configuration.
|
|
83
83
|
* @param {string=} batchId A tag for log.
|
|
84
|
-
* @return {!Promise
|
|
85
|
-
* succeeded.
|
|
84
|
+
* @return {!Promise<!BatchResult>}
|
|
86
85
|
*/
|
|
87
86
|
async uploadData(data, config, batchId = 'unnamed') {
|
|
88
87
|
const uploadConfig = Object.assign(
|
|
@@ -100,29 +99,38 @@ class Analytics {
|
|
|
100
99
|
this.logger.debug('Response: ', response);
|
|
101
100
|
const job = /** @type {Schema$Upload} */ response.data;
|
|
102
101
|
const uploadId = (/** @type {Schema$Upload} */job).id;
|
|
103
|
-
|
|
102
|
+
this.logger.info(
|
|
103
|
+
`Task [${batchId}] creates GA Data import job: ${uploadId}`);
|
|
104
104
|
const jobConfig = Object.assign({uploadId}, config);
|
|
105
105
|
const result = await Promise.race([
|
|
106
106
|
this.checkJobStatus(jobConfig),
|
|
107
107
|
wait(8 * 60 * 1000, job), // wait up to 8 minutes here
|
|
108
108
|
]);
|
|
109
|
+
/** @type {BatchResult} */ const batchResult = {};
|
|
109
110
|
switch ((/** @type {Schema$Upload} */ result).status) {
|
|
110
111
|
case 'FAILED':
|
|
111
112
|
this.logger.error('GA Data Import failed', result);
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
batchResult.result = false;
|
|
114
|
+
batchResult.errors = result.errors
|
|
115
|
+
|| [`Unknown reason. ID: ${uploadId}`];
|
|
116
|
+
break;
|
|
114
117
|
case 'COMPLETED':
|
|
115
118
|
this.logger.info(`GA Data Import job[${uploadId}] completed.`);
|
|
116
119
|
this.logger.debug('Response: ', result);
|
|
117
|
-
|
|
120
|
+
batchResult.result = true;
|
|
121
|
+
break;
|
|
118
122
|
case 'PENDING':
|
|
119
123
|
this.logger.info('GA Data Import pending.', result);
|
|
120
124
|
this.logger.info('Still will return true here.');
|
|
121
|
-
|
|
125
|
+
batchResult.result = true;
|
|
126
|
+
break;
|
|
122
127
|
default:
|
|
123
128
|
this.logger.error('Unknown results of GA Data Import: ', result);
|
|
124
|
-
|
|
129
|
+
batchResult.result = false;
|
|
130
|
+
batchResult.errors = [`Unknown status. ID: ${uploadId}`];
|
|
125
131
|
}
|
|
132
|
+
console.log(batchResult);
|
|
133
|
+
return batchResult;
|
|
126
134
|
}
|
|
127
135
|
|
|
128
136
|
/**
|
package/src/apis/auth_client.js
CHANGED
|
@@ -55,6 +55,8 @@ class AuthClient {
|
|
|
55
55
|
/**
|
|
56
56
|
* Create a new instance with given API scopes.
|
|
57
57
|
* @param {string|!Array<string>|!ReadonlyArray<string>} scopes
|
|
58
|
+
* @param {!Object<string,string>=} env The environment object to hold env
|
|
59
|
+
* variables.
|
|
58
60
|
*/
|
|
59
61
|
constructor(scopes, env = process.env) {
|
|
60
62
|
this.scopes = scopes;
|
|
@@ -152,7 +154,7 @@ class AuthClient {
|
|
|
152
154
|
* Returns the full path of a existent file whose path (relative or
|
|
153
155
|
* absolute) is the value of the given environment variable.
|
|
154
156
|
* @param {string} envName The name of environment variable for the file path.
|
|
155
|
-
* @param {!Object<string,string
|
|
157
|
+
* @param {!Object<string,string>=} env The environment object to hold env
|
|
156
158
|
* variables.
|
|
157
159
|
* @return {?string} Full path of the file what set as an environment variable.
|
|
158
160
|
*/
|
|
@@ -64,7 +64,7 @@ class MeasurementProtocol {
|
|
|
64
64
|
* @param {string} batchId The tag for log.
|
|
65
65
|
* @return {!Promise<boolean>}
|
|
66
66
|
*/
|
|
67
|
-
return (lines, batchId) => {
|
|
67
|
+
return async (lines, batchId) => {
|
|
68
68
|
const payload =
|
|
69
69
|
lines
|
|
70
70
|
.map((line) => {
|
|
@@ -85,24 +85,37 @@ class MeasurementProtocol {
|
|
|
85
85
|
body: payload,
|
|
86
86
|
headers: {'User-Agent': 'Tentacles/MeasurementProtocol-v1'}
|
|
87
87
|
};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
88
|
+
const response = await request(requestOptions);
|
|
89
|
+
console.log(response);
|
|
90
|
+
if (response.status < 200 || response.status >= 300) {
|
|
91
|
+
const errorMessages = [
|
|
92
|
+
`Measurement Protocol [${batchId}] didn't succeed.`,
|
|
93
|
+
`Get response code: ${response.status}`,
|
|
94
|
+
`response: ${response.data}`,
|
|
95
|
+
];
|
|
96
|
+
console.error(errorMessages.join('\n'));
|
|
97
|
+
throw new Error(`Status code not 2XX`);
|
|
98
|
+
}
|
|
99
|
+
this.logger.debug(`Configuration:`, config);
|
|
100
|
+
this.logger.debug(`Input Data: `, lines);
|
|
101
|
+
this.logger.debug(`Batch[${batchId}] status: ${response.status}`);
|
|
102
|
+
this.logger.debug(response.data);
|
|
103
|
+
// There is not enough information from the non-debug mode.
|
|
104
|
+
if (!this.debugMode) return true;
|
|
105
|
+
const failedHits = [];
|
|
106
|
+
const failedReasons = new Set();
|
|
107
|
+
const errorMessage = response.data.hitParsingResult
|
|
108
|
+
.forEach((result, index) => {
|
|
109
|
+
if (!result.valid) {
|
|
110
|
+
failedHits.push(lines[index]);
|
|
111
|
+
result.parserMessage.forEach(({description}) => {
|
|
112
|
+
failedReasons.add(description);
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
console.log(failedHits);
|
|
117
|
+
console.log(failedReasons);
|
|
118
|
+
return errorMessage;
|
|
106
119
|
};
|
|
107
120
|
};
|
|
108
121
|
|
package/src/components/utils.js
CHANGED
|
@@ -23,12 +23,23 @@ const {inspect} = require('util');
|
|
|
23
23
|
const {LoggingWinston} = require('@google-cloud/logging-winston');
|
|
24
24
|
const {CloudPlatformApis} = require('../apis/cloud_platform_apis.js');
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The result of a batch of data sent to target API.
|
|
28
|
+
*
|
|
29
|
+
* @typedef {{
|
|
30
|
+
* result: boolean,
|
|
31
|
+
* errors: (Array<string>|undefined),
|
|
32
|
+
* output: (Array<string>|undefined),
|
|
33
|
+
* }}
|
|
34
|
+
*/
|
|
35
|
+
let BatchResult;
|
|
36
|
+
|
|
26
37
|
/**
|
|
27
38
|
* Function which sends a batch of data. Takes two parameters:
|
|
28
39
|
* {!Array<string>} Data for single request. It should be guaranteed that it
|
|
29
40
|
* doesn't exceed quota limitation.
|
|
30
41
|
* {string} The tag for log.
|
|
31
|
-
* @typedef {function(!Array<string>,string): !Promise
|
|
42
|
+
* @typedef {function(!Array<string>,string): !Promise<!BatchResult>}
|
|
32
43
|
*/
|
|
33
44
|
let SendSingleBatch;
|
|
34
45
|
|
|
@@ -463,6 +474,7 @@ const changeNamingFromSnakeToLowerCamel = (name) => {
|
|
|
463
474
|
module.exports = {
|
|
464
475
|
getLogger,
|
|
465
476
|
wait,
|
|
477
|
+
BatchResult,
|
|
466
478
|
SendSingleBatch,
|
|
467
479
|
apiSpeedControl,
|
|
468
480
|
splitArray,
|