@google-cloud/nodejs-common 1.0.4 → 1.1.1-beta
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/README.md +46 -49
- package/bin/bigquery.sh +53 -0
- package/bin/google_ads.sh +115 -0
- package/bin/install_functions.sh +98 -25
- package/package.json +15 -14
- package/src/apis/ads_data_hub.js +4 -2
- package/src/apis/cloud_platform_apis.js +4 -4
- package/src/apis/doubleclick_bidmanager.js +21 -2
- package/src/apis/google_ads.js +98 -10
- package/src/apis/index.js +1 -1
- package/src/components/automl.js +36 -56
- package/src/components/scheduler.js +36 -24
- package/src/components/utils.js +1 -34
- package/src/components/vertex_ai.js +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# NodeJS Common Library
|
|
2
2
|
|
|
3
|
-
<!--* freshness: { owner: 'lushu' reviewed: '
|
|
3
|
+
<!--* freshness: { owner: 'lushu' reviewed: '2022-04-07' } *-->
|
|
4
4
|
|
|
5
5
|
A NodeJs common library for other projects, e.g. [GMP and Google Ads Connector]
|
|
6
6
|
and [Data Tasks Coordinator]. This library includes:
|
|
@@ -11,68 +11,65 @@ and [Data Tasks Coordinator]. This library includes:
|
|
|
11
11
|
1. Wrapper for some Google APIs for integration, mainly
|
|
12
12
|
for [GMP and Google Ads Connector]:
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
- Google Analytics data import
|
|
15
|
+
- Google Analytics measurement protocol
|
|
16
|
+
- Campaign Manager offline conversion upload
|
|
17
|
+
- Search Ads 360 conversions upload
|
|
18
|
+
- Google Ads click conversions upload
|
|
19
|
+
- Google Ads customer match upload
|
|
20
|
+
- Google Ads enhanced conversions upload
|
|
21
|
+
- Google Ads conversions scheduled uploads based on Google Sheets
|
|
22
|
+
- Measurement Protocol Google Analytics 4
|
|
22
23
|
|
|
23
24
|
1. Wrapper for some Google APIs for reporting, mainly
|
|
24
25
|
for [Data Tasks Coordinator]:
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
- Google Ads reporting
|
|
28
|
+
- Campaign Manager reporting
|
|
29
|
+
- Search Ads 360 reporting
|
|
30
|
+
- Display and Video 360 reporting
|
|
31
|
+
- YouTube Data API
|
|
32
|
+
- Ads Data Hub querying
|
|
32
33
|
|
|
33
34
|
1. Utilities wrapper class for Google Cloud Products:
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
- **Firestore Access Object**: Firestore has two modes which are excluded to
|
|
37
|
+
each other and can't be changed once selected in a Cloud Project[[2]].
|
|
38
|
+
This class, with its two successors offer a unified interface to operate
|
|
39
|
+
data objects on either Firestore or Datastore.
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
- **AutoMl Tables API**: Offers a unified entry to use this API based on
|
|
42
|
+
Google Cloud client library combined with REST requests to service
|
|
43
|
+
directly due to some functionalities missed in the client library.
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
- **Vertex AI API**: Offers a unified entry to use this API based on Google
|
|
46
|
+
Cloud client library.
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
- **Pub/Sub Utilities**: Offers utilities functions to create topics and
|
|
49
|
+
subscriptions for Pub/Sub, as well as the convenient way to publish a
|
|
50
|
+
message.
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
- **Storage Utilities**: Offers functions to manipulate the files on Cloud
|
|
53
|
+
Storage. The main functions are:
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
- Reading a given length (or slightly less) content without breaking a
|
|
56
|
+
line;
|
|
57
|
+
- Splitting a file into multiple files with the given length (or
|
|
58
|
+
slightly less) without breaking a line;
|
|
59
|
+
- Merging files into one file.
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
- **Cloud Scheduler Adapter**: A wrapper to pause and resume Cloud Scheduler
|
|
62
|
+
jobs.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
- **Cloud Functions Adapter**: Cloud Functions have different parameters in
|
|
65
|
+
different environments, e.g. Node6 vs Node8[[1]]. This utility file offers
|
|
66
|
+
an adapter to wrap a Node8 Cloud Functions into Node6 and Node8 compatible
|
|
67
|
+
functions.
|
|
67
68
|
|
|
68
69
|
1. A share library for [Bash] to facilitate installation tasks.
|
|
69
70
|
|
|
70
|
-
[
|
|
71
|
-
|
|
72
|
-
[
|
|
73
|
-
|
|
74
|
-
[
|
|
75
|
-
|
|
76
|
-
[2]:https://cloud.google.com/datastore/docs/concepts/overview#comparison_with_traditional_databases
|
|
77
|
-
|
|
78
|
-
[Bash]:https://www.gnu.org/software/bash/
|
|
71
|
+
[gmp and google ads connector]: https://github.com/GoogleCloudPlatform/cloud-for-marketing/tree/master/marketing-analytics/activation/gmp-googleads-connector
|
|
72
|
+
[data tasks coordinator]: https://github.com/GoogleCloudPlatform/cloud-for-marketing/tree/master/marketing-analytics/activation/data-tasks-coordinator
|
|
73
|
+
[1]: https://cloud.google.com/functions/docs/writing/background#functions-writing-background-hello-pubsub-node8-10
|
|
74
|
+
[2]: https://cloud.google.com/datastore/docs/concepts/overview#comparison_with_traditional_databases
|
|
75
|
+
[bash]: https://www.gnu.org/software/bash/
|
package/bin/bigquery.sh
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2022 Google Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
#######################################
|
|
18
|
+
# Checks whether the BigQuery object (table or view) exists.
|
|
19
|
+
# Globals:
|
|
20
|
+
# GCP_PROJECT
|
|
21
|
+
# DATASET
|
|
22
|
+
# BIGQUERY_LOG_TABLE
|
|
23
|
+
# Arguments:
|
|
24
|
+
# None
|
|
25
|
+
#######################################
|
|
26
|
+
check_existence_in_bigquery() {
|
|
27
|
+
bq show "${1}" >/dev/null 2>&1
|
|
28
|
+
printf '%d' $?
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#######################################
|
|
32
|
+
# Creates or updates the BigQuery view.
|
|
33
|
+
# Globals:
|
|
34
|
+
# GCP_PROJECT
|
|
35
|
+
# DATASET
|
|
36
|
+
# Arguments:
|
|
37
|
+
# The name of view.
|
|
38
|
+
# The query of view.
|
|
39
|
+
#######################################
|
|
40
|
+
create_or_update_view() {
|
|
41
|
+
local viewName viewQuery
|
|
42
|
+
viewName="${1}"
|
|
43
|
+
viewQuery=${2}
|
|
44
|
+
local action="mk"
|
|
45
|
+
if [[ $(check_existence_in_bigquery "${DATASET}.${viewName}") -eq 0 ]]; then
|
|
46
|
+
action="update"
|
|
47
|
+
fi
|
|
48
|
+
bq "${action}" \
|
|
49
|
+
--use_legacy_sql=false \
|
|
50
|
+
--view "${viewQuery}" \
|
|
51
|
+
--project_id ${GCP_PROJECT} \
|
|
52
|
+
"${DATASET}.${viewName}"
|
|
53
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2022 Google Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
# Google Ads API version
|
|
18
|
+
GOOGLE_ADS_API_VERSION=10
|
|
19
|
+
|
|
20
|
+
#######################################
|
|
21
|
+
# Verify whether the current OAuth token, CID and developer token can work.
|
|
22
|
+
# Globals:
|
|
23
|
+
# None
|
|
24
|
+
# Arguments:
|
|
25
|
+
# MCC CID
|
|
26
|
+
# Developer token
|
|
27
|
+
#######################################
|
|
28
|
+
validate_googleads_account() {
|
|
29
|
+
local cid developerToken accessToken request response
|
|
30
|
+
cid=${1}
|
|
31
|
+
developerToken=${2}
|
|
32
|
+
accessToken=$(get_oauth_access_token)
|
|
33
|
+
request=(
|
|
34
|
+
-H "Accept: application/json"
|
|
35
|
+
-H "Content-Type: application/json"
|
|
36
|
+
-H "developer-token: ${developerToken}"
|
|
37
|
+
-H "Authorization: Bearer ${accessToken}"
|
|
38
|
+
-X POST "https://googleads.googleapis.com/v${GOOGLE_ADS_API_VERSION}/customers/${cid}/googleAds:search"
|
|
39
|
+
-d '{"query": "SELECT customer.id FROM customer"}'
|
|
40
|
+
)
|
|
41
|
+
response=$(curl "${request[@]}" 2>/dev/null)
|
|
42
|
+
local errorCode errorMessage
|
|
43
|
+
errorCode=$(get_value_from_json_string "${response}" "error.code")
|
|
44
|
+
if [[ -n "${errorCode}" ]]; then
|
|
45
|
+
errorMessage=$(get_value_from_json_string "${response}" "error.message")
|
|
46
|
+
printf '%s\n' "Validate failed: ${errorMessage}" >&2
|
|
47
|
+
return 1
|
|
48
|
+
fi
|
|
49
|
+
return 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#######################################
|
|
53
|
+
# Let user input MCC CID and developer token for cronjob(s).
|
|
54
|
+
# Globals:
|
|
55
|
+
# MCC_CIDS
|
|
56
|
+
# DEVELOPER_TOKEN
|
|
57
|
+
# Arguments:
|
|
58
|
+
# None
|
|
59
|
+
#######################################
|
|
60
|
+
set_google_ads_account() {
|
|
61
|
+
printf '%s\n' "Setting up Google Ads account information..."
|
|
62
|
+
local developToken mccCids
|
|
63
|
+
while :; do
|
|
64
|
+
# Developer token
|
|
65
|
+
while [[ -z ${developToken} ]]; do
|
|
66
|
+
printf '%s' " Enter the developer token[${DEVELOPER_TOKEN}]: "
|
|
67
|
+
read -r input
|
|
68
|
+
developToken="${input:-${DEVELOPER_TOKEN}}"
|
|
69
|
+
done
|
|
70
|
+
DEVELOPER_TOKEN="${developToken}"
|
|
71
|
+
mccCids=""
|
|
72
|
+
# MCC CIDs
|
|
73
|
+
while :; do
|
|
74
|
+
printf '%s' " Enter the MCC CID: "
|
|
75
|
+
read -r input
|
|
76
|
+
if [[ -z ${input} ]]; then
|
|
77
|
+
continue
|
|
78
|
+
fi
|
|
79
|
+
input="$(printf '%s' "${input}" | sed -r 's/-//g')"
|
|
80
|
+
printf '%s' " validating ${input}...... "
|
|
81
|
+
validate_googleads_account ${input} ${DEVELOPER_TOKEN}
|
|
82
|
+
if [[ $? -eq 1 ]]; then
|
|
83
|
+
printf '%s\n' "failed.
|
|
84
|
+
Press 'd' to re-enter developer token ["${developToken}"] or
|
|
85
|
+
'C' to continue with this MCC CID or
|
|
86
|
+
any other key to enter another MCC CID..."
|
|
87
|
+
local any
|
|
88
|
+
read -n1 -s any
|
|
89
|
+
if [[ "${any}" == "d" ]]; then
|
|
90
|
+
developToken=""
|
|
91
|
+
continue 2
|
|
92
|
+
elif [[ "${any}" == "C" ]]; then
|
|
93
|
+
printf '%s\n' "WARNING! Continue with FAILED MCC ${input}."
|
|
94
|
+
else
|
|
95
|
+
continue
|
|
96
|
+
fi
|
|
97
|
+
else
|
|
98
|
+
printf '%s\n' "succeeded."
|
|
99
|
+
fi
|
|
100
|
+
mccCids+=",${input}"
|
|
101
|
+
printf '%s' " Do you want to add another MCC CID? [Y/n]: "
|
|
102
|
+
read -r input
|
|
103
|
+
if [[ ${input} == 'n' || ${input} == 'N' ]]; then
|
|
104
|
+
break
|
|
105
|
+
fi
|
|
106
|
+
done
|
|
107
|
+
# Left Shift one position to remove the first comma.
|
|
108
|
+
# After shifting, MCC_CIDS would like "11111,22222".
|
|
109
|
+
MCC_CIDS="${mccCids:1}"
|
|
110
|
+
printf '%s\n' "Using Google Ads MCC CIDs: ${MCC_CIDS}."
|
|
111
|
+
break
|
|
112
|
+
done
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
printf '%s\n' "Google Ads Bash Library is loaded."
|
package/bin/install_functions.sh
CHANGED
|
@@ -173,7 +173,7 @@ project ID: [${current_project}]"
|
|
|
173
173
|
project=${project:-"${current_project}"}
|
|
174
174
|
target_project=${project}
|
|
175
175
|
fi
|
|
176
|
-
if [[ -
|
|
176
|
+
if [[ -z ${current_project} || \
|
|
177
177
|
${current_project} != "${target_project}" ]];then
|
|
178
178
|
printf '%s' "Setting the Google Cloud project to [${target_project}]..."
|
|
179
179
|
gcloud config set project "${target_project}"
|
|
@@ -573,7 +573,7 @@ API(s):"
|
|
|
573
573
|
printf '%s\n' "OK. OAuth is required by selected API(s)."
|
|
574
574
|
return 0
|
|
575
575
|
fi
|
|
576
|
-
printf '%s\n' "Selected API(s) require authentication.
|
|
576
|
+
printf '%s\n' "Selected API(s) require authentication. Choose the \
|
|
577
577
|
authentication method:"
|
|
578
578
|
local auths=("Service Account (recommended)" "OAuth")
|
|
579
579
|
select auth in "${auths[@]}"; do
|
|
@@ -604,28 +604,40 @@ check_permissions() {
|
|
|
604
604
|
(( STEP += 1 ))
|
|
605
605
|
printf '%s\n' "Step ${STEP}: Checking current user's access..."
|
|
606
606
|
local role error
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
607
|
+
while :; do
|
|
608
|
+
error=0
|
|
609
|
+
for role in "${!GOOGLE_CLOUD_PERMISSIONS[@]}"; do
|
|
610
|
+
printf '%s' " Checking permissions for ${role}... "
|
|
611
|
+
local permissions
|
|
612
|
+
permissions=(${GOOGLE_CLOUD_PERMISSIONS[${role}]})
|
|
613
|
+
local missed
|
|
614
|
+
missed=$(get_number_of_missed_permissions "${permissions[@]}")
|
|
615
|
+
if [[ $missed -gt 0 ]]; then
|
|
616
|
+
message="missed ${missed}, failed"
|
|
617
|
+
error=1
|
|
618
|
+
else
|
|
619
|
+
message='successfully'
|
|
620
|
+
fi
|
|
621
|
+
printf '%s\n' " ${message}."
|
|
622
|
+
done
|
|
623
|
+
if [[ ${error} -gt 0 ]]; then
|
|
624
|
+
printf '%s\n' "Permissions check failed."
|
|
625
|
+
printf '%s\n' "Would you like to login with another account? [Y/n]: "
|
|
626
|
+
local reLogin
|
|
627
|
+
read -r reLogin
|
|
628
|
+
reLogin=${reLogin:-"Y"}
|
|
629
|
+
if [[ ${reLogin} == "Y" || ${reLogin} == "y" ]]; then
|
|
630
|
+
gcloud auth login
|
|
631
|
+
continue
|
|
632
|
+
else
|
|
633
|
+
return 1
|
|
634
|
+
fi
|
|
616
635
|
else
|
|
617
|
-
|
|
636
|
+
echo "OK. Permissions check passed for Google Cloud project \
|
|
637
|
+
[${GCP_PROJECT}]."
|
|
638
|
+
return 0
|
|
618
639
|
fi
|
|
619
|
-
printf '%s\n' " ${message}."
|
|
620
640
|
done
|
|
621
|
-
if [[ ${error} -gt 0 ]]; then
|
|
622
|
-
printf '%s\n' "Permissions check failed."
|
|
623
|
-
return 1
|
|
624
|
-
else
|
|
625
|
-
echo "OK. Permissions check passed for Google Cloud project \
|
|
626
|
-
[${GCP_PROJECT}]."
|
|
627
|
-
return 0
|
|
628
|
-
fi
|
|
629
641
|
}
|
|
630
642
|
|
|
631
643
|
#######################################
|
|
@@ -1129,6 +1141,7 @@ Project. Continuing to enter another bucket..."
|
|
|
1129
1141
|
fi
|
|
1130
1142
|
done
|
|
1131
1143
|
declare -g "${gcsName}=${bucket}"
|
|
1144
|
+
confirm_bucket_lifecycle "${bucket}"
|
|
1132
1145
|
}
|
|
1133
1146
|
|
|
1134
1147
|
#######################################
|
|
@@ -1149,6 +1162,58 @@ confirm_bucket_with_location() {
|
|
|
1149
1162
|
confirm_located_bucket ${gcsName} ${locationName}
|
|
1150
1163
|
}
|
|
1151
1164
|
|
|
1165
|
+
#######################################
|
|
1166
|
+
# Manage the lifecycle of a GCS bucket: setting or removing the GCS lifecycle
|
|
1167
|
+
# rule of 'age'.
|
|
1168
|
+
# See: https://cloud.google.com/storage/docs/lifecycle#age
|
|
1169
|
+
# Arguments:
|
|
1170
|
+
# Bucket name
|
|
1171
|
+
#######################################
|
|
1172
|
+
confirm_bucket_lifecycle() {
|
|
1173
|
+
local bucket bucketMetadata lifecycle
|
|
1174
|
+
bucket="${1}"
|
|
1175
|
+
bucketMetadata="$(get_bucket_metadata "${bucket}")"
|
|
1176
|
+
lifecycle="$(get_value_from_json_string "${bucketMetadata}" "lifecycle")"
|
|
1177
|
+
if [[ -n "${lifecycle}" ]]; then
|
|
1178
|
+
printf '%s\n' "There are lifecycle rules in this bucket: ${lifecycle}."
|
|
1179
|
+
printf '%s' "Would you like to overwrite it? [N/y]:"
|
|
1180
|
+
local confirmContinue
|
|
1181
|
+
read -r confirmContinue
|
|
1182
|
+
confirmContinue=${confirmContinue:-"N"}
|
|
1183
|
+
if [[ ${confirmContinue} == "N" || ${confirmContinue} == "n" ]]; then
|
|
1184
|
+
return 0
|
|
1185
|
+
fi
|
|
1186
|
+
else
|
|
1187
|
+
printf '%s\n' "There is no lifecycle rules in this bucket."
|
|
1188
|
+
printf '%s' "Would you like to create it? [Y/n]:"
|
|
1189
|
+
local confirmContinue
|
|
1190
|
+
read -r confirmContinue
|
|
1191
|
+
confirmContinue=${confirmContinue:-"Y"}
|
|
1192
|
+
if [[ ${confirmContinue} == "N" || ${confirmContinue} == "n" ]]; then
|
|
1193
|
+
return 0
|
|
1194
|
+
fi
|
|
1195
|
+
fi
|
|
1196
|
+
while :; do
|
|
1197
|
+
printf '%s' "Enter the number of days that a file will be kept before it \
|
|
1198
|
+
is automatically removed in the bucket[${bucket}]. (enter 0 to remove all \
|
|
1199
|
+
existing lifecycle rules): "
|
|
1200
|
+
local days
|
|
1201
|
+
read -r days
|
|
1202
|
+
days=${days}
|
|
1203
|
+
if [[ "${days}" =~ ^[0-9]+$ ]]; then
|
|
1204
|
+
local lifecycle
|
|
1205
|
+
if [[ "${days}" == "0" ]]; then
|
|
1206
|
+
lifecycle="{}"
|
|
1207
|
+
else
|
|
1208
|
+
lifecycle='{"rule":[{"action":{"type":"Delete"},"condition":{"age":'\
|
|
1209
|
+
"${days}}}]}"
|
|
1210
|
+
fi
|
|
1211
|
+
gsutil lifecycle set /dev/stdin gs://${bucket} <<< ${lifecycle}
|
|
1212
|
+
return $?
|
|
1213
|
+
fi
|
|
1214
|
+
done
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1152
1217
|
#######################################
|
|
1153
1218
|
# Confirm the monitored folder.
|
|
1154
1219
|
# Globals:
|
|
@@ -1507,6 +1572,7 @@ set_authentication_env_for_cloud_functions() {
|
|
|
1507
1572
|
create_or_update_cloud_scheduler_for_pubsub(){
|
|
1508
1573
|
check_authentication
|
|
1509
1574
|
quit_if_failed $?
|
|
1575
|
+
local location_flag="--location=${REGION}"
|
|
1510
1576
|
local scheduler_flag=()
|
|
1511
1577
|
scheduler_flag+=(--schedule="$2")
|
|
1512
1578
|
scheduler_flag+=(--time-zone="$3")
|
|
@@ -1514,13 +1580,13 @@ create_or_update_cloud_scheduler_for_pubsub(){
|
|
|
1514
1580
|
scheduler_flag+=(--message-body="$5")
|
|
1515
1581
|
local exist_job
|
|
1516
1582
|
exist_job=($(gcloud scheduler jobs list --filter="name~${1}" \
|
|
1517
|
-
--format="value(state)"))
|
|
1583
|
+
--format="value(state)" "${location_flag}"))
|
|
1518
1584
|
local action needPause
|
|
1519
1585
|
if [[ ${#exist_job[@]} -gt 0 ]]; then
|
|
1520
1586
|
action="update"
|
|
1521
1587
|
scheduler_flag+=(--update-attributes=$6)
|
|
1522
1588
|
if [[ "${exist_job[0]}" == "PAUSED" ]]; then
|
|
1523
|
-
gcloud scheduler jobs resume "${1}"
|
|
1589
|
+
gcloud scheduler jobs resume "${1}" "${location_flag}"
|
|
1524
1590
|
if [[ $? -gt 0 ]]; then
|
|
1525
1591
|
printf '%s\n' "Failed to resume paused Cloud Scheduler job [${1}]."
|
|
1526
1592
|
return 1
|
|
@@ -1531,9 +1597,9 @@ create_or_update_cloud_scheduler_for_pubsub(){
|
|
|
1531
1597
|
action="create"
|
|
1532
1598
|
scheduler_flag+=(--attributes=$6)
|
|
1533
1599
|
fi
|
|
1534
|
-
gcloud scheduler jobs ${action} pubsub "$1" "${scheduler_flag[@]}"
|
|
1600
|
+
gcloud scheduler jobs ${action} pubsub "$1" "${scheduler_flag[@]}" "${location_flag}"
|
|
1535
1601
|
if [[ "${needPause}" == "true" ]]; then
|
|
1536
|
-
gcloud scheduler jobs pause "${1}"
|
|
1602
|
+
gcloud scheduler jobs pause "${1}" "${location_flag}"
|
|
1537
1603
|
fi
|
|
1538
1604
|
}
|
|
1539
1605
|
|
|
@@ -1921,3 +1987,10 @@ join_string_array() {
|
|
|
1921
1987
|
shift
|
|
1922
1988
|
printf %s "$first" "${@/#/$separator}"
|
|
1923
1989
|
}
|
|
1990
|
+
|
|
1991
|
+
# Import other bash files.
|
|
1992
|
+
_SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
1993
|
+
source "${_SELF}/google_ads.sh"
|
|
1994
|
+
source "${_SELF}/bigquery.sh"
|
|
1995
|
+
|
|
1996
|
+
printf '%s\n' "Common Bash Library is loaded."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@google-cloud/nodejs-common",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1-beta",
|
|
4
4
|
"description": "A NodeJs common library for solutions based on Cloud Functions",
|
|
5
5
|
"author": "Google Inc.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -16,25 +16,26 @@
|
|
|
16
16
|
},
|
|
17
17
|
"homepage": "https://github.com/GoogleCloudPlatform/cloud-for-marketing/blob/master/marketing-analytics/activation/common-libs/nodejs-common/README.md",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@google-cloud/aiplatform": "^1.
|
|
20
|
-
"@google-cloud/automl": "^2.5.
|
|
21
|
-
"@google-cloud/bigquery": "^5.
|
|
19
|
+
"@google-cloud/aiplatform": "^1.19.0",
|
|
20
|
+
"@google-cloud/automl": "^2.5.2",
|
|
21
|
+
"@google-cloud/bigquery": "^5.12.0",
|
|
22
22
|
"@google-cloud/datastore": "^6.6.2",
|
|
23
|
-
"@google-cloud/firestore": "^
|
|
24
|
-
"@google-cloud/logging-winston": "^4.
|
|
25
|
-
"@google-cloud/pubsub": "^2.
|
|
26
|
-
"@google-cloud/storage": "^5.
|
|
23
|
+
"@google-cloud/firestore": "^5.0.2",
|
|
24
|
+
"@google-cloud/logging-winston": "^4.2.2",
|
|
25
|
+
"@google-cloud/pubsub": "^2.19.0",
|
|
26
|
+
"@google-cloud/storage": "^5.18.3",
|
|
27
|
+
"@google-cloud/scheduler": "^2.3.0",
|
|
27
28
|
"gaxios": "^4.3.2",
|
|
28
|
-
"google-ads-api": "^
|
|
29
|
-
"google-ads-node":
|
|
30
|
-
"google-auth-library": "^7.
|
|
31
|
-
"googleapis": "^
|
|
29
|
+
"google-ads-api": "^10.0.1",
|
|
30
|
+
"google-ads-node":"^8.0.1",
|
|
31
|
+
"google-auth-library": "^7.14.1",
|
|
32
|
+
"googleapis": "^100.0.0",
|
|
32
33
|
"soap": "^0.43.0",
|
|
33
|
-
"winston": "^3.
|
|
34
|
+
"winston": "^3.7.2",
|
|
34
35
|
"lodash": "^4.17.21"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
|
-
"jasmine": "^
|
|
38
|
+
"jasmine": "^4.0.2"
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
41
|
"test": "node node_modules/jasmine/bin/jasmine"
|
package/src/apis/ads_data_hub.js
CHANGED
|
@@ -37,9 +37,11 @@ class AdsDataHub {
|
|
|
37
37
|
*
|
|
38
38
|
* @param {GaxiosOptions|undefined=} options Used to setup for tests.
|
|
39
39
|
* @param {string|undefined=} customerId ADH customer id.
|
|
40
|
+
* @param {!Object<string,string>=} env The environment object to hold env
|
|
41
|
+
* variables.
|
|
40
42
|
*/
|
|
41
|
-
constructor(options, customerId = undefined) {
|
|
42
|
-
const authClient = new AuthClient(API_SCOPES);
|
|
43
|
+
constructor(options, customerId = undefined, env = process.env) {
|
|
44
|
+
const authClient = new AuthClient(API_SCOPES, env);
|
|
43
45
|
this.auth = authClient.getDefaultAuth();
|
|
44
46
|
/** @const{GaxiosOptions} */ this.options = options || {};
|
|
45
47
|
/** @const{string|undefined=} */ this.customerId = customerId;
|
|
@@ -32,11 +32,11 @@ const API_VERSION = 'v1';
|
|
|
32
32
|
* Google cloud client libraries.
|
|
33
33
|
*/
|
|
34
34
|
class CloudPlatformApis {
|
|
35
|
-
constructor(
|
|
35
|
+
constructor(env = process.env) {
|
|
36
36
|
/** @const {!AuthClient} */
|
|
37
|
-
const authClient = new AuthClient(API_SCOPES);
|
|
38
|
-
this.auth = authClient.
|
|
39
|
-
this.projectId =
|
|
37
|
+
const authClient = new AuthClient(API_SCOPES, env);
|
|
38
|
+
this.auth = authClient.getDefaultAuth();
|
|
39
|
+
this.projectId = env['GCP_PROJECT'];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -56,8 +56,13 @@ let RequestBody;
|
|
|
56
56
|
* https://developers.google.com/bid-manager/how-tos/authorizing
|
|
57
57
|
*/
|
|
58
58
|
class DoubleClickBidManager {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
/**
|
|
60
|
+
* @constructor
|
|
61
|
+
* @param {!Object<string,string>=} env The environment object to hold env
|
|
62
|
+
* variables.
|
|
63
|
+
*/
|
|
64
|
+
constructor(env = process.env) {
|
|
65
|
+
const authClient = new AuthClient(API_SCOPES, env);
|
|
61
66
|
const auth = authClient.getDefaultAuth();
|
|
62
67
|
/** @const {!google.doubleclickbidmanager} */
|
|
63
68
|
this.instance = google.doubleclickbidmanager({
|
|
@@ -104,6 +109,20 @@ class DoubleClickBidManager {
|
|
|
104
109
|
return response.data.queryId;
|
|
105
110
|
}
|
|
106
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Deletes a query.
|
|
114
|
+
* @param {number} queryId
|
|
115
|
+
* @return {!Promise<boolean>} Whether the query was deleted.
|
|
116
|
+
*/
|
|
117
|
+
async deleteQuery(queryId) {
|
|
118
|
+
try {
|
|
119
|
+
await this.instance.queries.deletequery({ queryId });
|
|
120
|
+
return true;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error(error);
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
module.exports = {
|
package/src/apis/google_ads.js
CHANGED
|
@@ -31,6 +31,8 @@ const {
|
|
|
31
31
|
services: {
|
|
32
32
|
UploadClickConversionsRequest,
|
|
33
33
|
UploadClickConversionsResponse,
|
|
34
|
+
UploadConversionAdjustmentsRequest,
|
|
35
|
+
UploadConversionAdjustmentsResponse,
|
|
34
36
|
UploadUserDataRequest,
|
|
35
37
|
UploadUserDataResponse,
|
|
36
38
|
UserDataOperation,
|
|
@@ -51,8 +53,9 @@ const API_SCOPES = Object.freeze(['https://www.googleapis.com/auth/adwords',]);
|
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* List of properties that will be taken from the data file as elements of a
|
|
54
|
-
* conversion.
|
|
56
|
+
* conversion or a conversion adjustment.
|
|
55
57
|
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/ClickConversion
|
|
58
|
+
* @see https://developers.google.com/google-ads/api/reference/rpc/latest/ConversionAdjustment
|
|
56
59
|
* @type {Array<string>}
|
|
57
60
|
*/
|
|
58
61
|
const PICKED_PROPERTIES = [
|
|
@@ -65,6 +68,10 @@ const PICKED_PROPERTIES = [
|
|
|
65
68
|
'conversion_value',
|
|
66
69
|
'currency_code',
|
|
67
70
|
'order_id',
|
|
71
|
+
'adjustment_type',
|
|
72
|
+
'adjustment_date_time',
|
|
73
|
+
'user_agent',
|
|
74
|
+
'gclid_date_time_pair',
|
|
68
75
|
];
|
|
69
76
|
|
|
70
77
|
/**
|
|
@@ -88,9 +95,11 @@ const IDENTIFIERS = [
|
|
|
88
95
|
const MAX_IDENTIFIERS_PER_USER = 20;
|
|
89
96
|
|
|
90
97
|
/**
|
|
91
|
-
* Configuration for uploading click conversions
|
|
98
|
+
* Configuration for uploading click conversions or conversion adjustments for
|
|
99
|
+
* Google Ads, includes:
|
|
92
100
|
* gclid, conversion_action, conversion_date_time, conversion_value,
|
|
93
|
-
* currency_code, order_id, external_attribution_data,
|
|
101
|
+
* currency_code, order_id, external_attribution_data,
|
|
102
|
+
* adjustment_type, adjustment_date_time, user_agent, gclid_date_time_pair, etc.
|
|
94
103
|
* @see PICKED_PROPERTIES
|
|
95
104
|
*
|
|
96
105
|
* Other properties that will be used to build the conversions but not picked by
|
|
@@ -116,12 +125,15 @@ const MAX_IDENTIFIERS_PER_USER = 20;
|
|
|
116
125
|
* conversion_value: number,
|
|
117
126
|
* currency_code:(string|undefined),
|
|
118
127
|
* order_id: (string|undefined),
|
|
119
|
-
*
|
|
128
|
+
* adjustment_type: (string|undefined),
|
|
129
|
+
* adjustment_date_time: (!ConversionAdjustmentType|undefined),
|
|
130
|
+
* user_agent: (string|undefined),
|
|
131
|
+
* user_identifier_source:(!UserIdentifierSource|undefined),
|
|
120
132
|
* custom_variable_tags:(!Array<string>|undefined),
|
|
121
133
|
* customVariables:(!Object<string,string>|undefined),
|
|
122
134
|
* }}
|
|
123
135
|
*/
|
|
124
|
-
let
|
|
136
|
+
let ConversionConfig;
|
|
125
137
|
|
|
126
138
|
/**
|
|
127
139
|
* Configuration for uploading customer match to Google Ads, includes:
|
|
@@ -255,7 +267,7 @@ class GoogleAds {
|
|
|
255
267
|
* of click conversions.
|
|
256
268
|
* @param {string} customerId
|
|
257
269
|
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
258
|
-
* @param {!
|
|
270
|
+
* @param {!ConversionConfig} adsConfig Default click conversion params
|
|
259
271
|
* @return {!SendSingleBatch} Function which can send a batch of hits to
|
|
260
272
|
* Google Ads API.
|
|
261
273
|
*/
|
|
@@ -268,7 +280,7 @@ class GoogleAds {
|
|
|
268
280
|
* @return {!BatchResult}
|
|
269
281
|
*/
|
|
270
282
|
return async (lines, batchId) => {
|
|
271
|
-
/** @type {!Array<
|
|
283
|
+
/** @type {!Array<ConversionConfig>} */
|
|
272
284
|
const conversions = lines.map(
|
|
273
285
|
(line) => buildClickConversionFromLine(line, adsConfig, customerId));
|
|
274
286
|
/** @const {BatchResult} */
|
|
@@ -300,6 +312,57 @@ class GoogleAds {
|
|
|
300
312
|
}
|
|
301
313
|
}
|
|
302
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Returns the function to send out a request to Google Ads API with a batch
|
|
317
|
+
* of conversion adjustments.
|
|
318
|
+
* @param {string} customerId
|
|
319
|
+
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
320
|
+
* @param {!ConversionConfig} adsConfig Default conversion adjustments
|
|
321
|
+
* params.
|
|
322
|
+
* @return {!SendSingleBatch} Function which can send a batch of hits to
|
|
323
|
+
* Google Ads API.
|
|
324
|
+
*/
|
|
325
|
+
getUploadConversionAdjustmentFn(customerId, loginCustomerId, adsConfig) {
|
|
326
|
+
/**
|
|
327
|
+
* Sends a batch of hits to Google Ads API.
|
|
328
|
+
* @param {!Array<string>} lines Data for single request. It should be
|
|
329
|
+
* guaranteed that it doesn't exceed quota limitation.
|
|
330
|
+
* @param {string} batchId The tag for log.
|
|
331
|
+
* @return {!BatchResult}
|
|
332
|
+
*/
|
|
333
|
+
return async (lines, batchId) => {
|
|
334
|
+
/** @type {!Array<ConversionConfig>} */
|
|
335
|
+
const conversions = lines.map(
|
|
336
|
+
(line) => buildClickConversionFromLine(line, adsConfig, customerId));
|
|
337
|
+
/** @const {BatchResult} */
|
|
338
|
+
const batchResult = {
|
|
339
|
+
result: true,
|
|
340
|
+
numberOfLines: lines.length,
|
|
341
|
+
};
|
|
342
|
+
try {
|
|
343
|
+
const response = await this.uploadConversionAdjustments(conversions,
|
|
344
|
+
customerId, loginCustomerId);
|
|
345
|
+
const {results, partial_failure_error: failed} = response;
|
|
346
|
+
if (this.logger.isDebugEnabled()) {
|
|
347
|
+
const orderId = results.map((conversion) => conversion.order_id);
|
|
348
|
+
this.logger.debug('Uploaded order_id:', orderId);
|
|
349
|
+
}
|
|
350
|
+
if (failed) {
|
|
351
|
+
this.logger.info('partial_failure_error:', failed.message);
|
|
352
|
+
const failures = failed.details.map(
|
|
353
|
+
({value}) => GoogleAdsFailure.decode(value));
|
|
354
|
+
this.extraFailedLines_(batchResult, failures, lines, 0);
|
|
355
|
+
}
|
|
356
|
+
return batchResult;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
this.logger.error(
|
|
359
|
+
`Error in upload conversion adjustments batch: ${batchId}`, error);
|
|
360
|
+
this.updateBatchResultWithError_(batchResult, error, lines, 0);
|
|
361
|
+
return batchResult;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
303
366
|
/**
|
|
304
367
|
* Updates the BatchResult based on errors.
|
|
305
368
|
*
|
|
@@ -434,7 +497,7 @@ class GoogleAds {
|
|
|
434
497
|
* Uploads click conversions to google ads account.
|
|
435
498
|
* It requires an array of click conversions and customer id.
|
|
436
499
|
* In DEBUG mode, this function will only validate the conversions.
|
|
437
|
-
* @param {Array<
|
|
500
|
+
* @param {Array<ConversionConfig>} clickConversions ClickConversions
|
|
438
501
|
* @param {string} customerId
|
|
439
502
|
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
440
503
|
* @return {!Promise<!UploadClickConversionsResponse>}
|
|
@@ -451,6 +514,31 @@ class GoogleAds {
|
|
|
451
514
|
return customer.conversionUploads.uploadClickConversions(request);
|
|
452
515
|
}
|
|
453
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Uploads conversion adjustments to google ads account.
|
|
519
|
+
* It requires an array of conversion adjustments and customer id.
|
|
520
|
+
* In DEBUG mode, this function will only validate the conversion adjustments.
|
|
521
|
+
* @param {Array<ConversionAdjustment>} conversionAdjustments Conversion
|
|
522
|
+
* adjustments.
|
|
523
|
+
* @param {string} customerId
|
|
524
|
+
* @param {string} loginCustomerId Login customer account ID (Mcc Account id).
|
|
525
|
+
* @return {!Promise<!UploadConversionAdjustmentsResponse>}
|
|
526
|
+
*/
|
|
527
|
+
uploadConversionAdjustments(conversionAdjustments, customerId,
|
|
528
|
+
loginCustomerId) {
|
|
529
|
+
this.logger.debug('Upload conversion adjustments for customerId:',
|
|
530
|
+
customerId);
|
|
531
|
+
const customer = this.getGoogleAdsApiCustomer_(loginCustomerId, customerId);
|
|
532
|
+
const request = new UploadConversionAdjustmentsRequest({
|
|
533
|
+
conversion_adjustments: conversionAdjustments,
|
|
534
|
+
customer_id: customerId,
|
|
535
|
+
validate_only: this.debugMode, // when true makes no changes
|
|
536
|
+
partial_failure: true, // Will still create the non-failed entities
|
|
537
|
+
});
|
|
538
|
+
return customer.conversionAdjustmentUploads.uploadConversionAdjustments(
|
|
539
|
+
request);
|
|
540
|
+
}
|
|
541
|
+
|
|
454
542
|
/**
|
|
455
543
|
* Returns the id of Conversion Custom Variable with the given tag.
|
|
456
544
|
* @param {string} tag Custom Variable tag.
|
|
@@ -622,7 +710,7 @@ class GoogleAds {
|
|
|
622
710
|
/**
|
|
623
711
|
* Returns a conversion object based the given config and line data.
|
|
624
712
|
* @param {string} line A JSON string of a conversion data.
|
|
625
|
-
* @param {
|
|
713
|
+
* @param {ConversionConfig} config Default click conversion params
|
|
626
714
|
* @param {string} customerId
|
|
627
715
|
* @return {object} A conversion
|
|
628
716
|
*/
|
|
@@ -657,7 +745,7 @@ const buildClickConversionFromLine = (line, config, customerId) => {
|
|
|
657
745
|
}
|
|
658
746
|
|
|
659
747
|
module.exports = {
|
|
660
|
-
|
|
748
|
+
ConversionConfig,
|
|
661
749
|
CustomerMatchRecord,
|
|
662
750
|
CustomerMatchConfig,
|
|
663
751
|
GoogleAds,
|
package/src/apis/index.js
CHANGED
|
@@ -88,7 +88,7 @@ exports.bigquery = require('./bigquery.js');
|
|
|
88
88
|
* APIs integration class for Google Ads.
|
|
89
89
|
* @const {{
|
|
90
90
|
* GoogleAds:!GoogleAds,
|
|
91
|
-
*
|
|
91
|
+
* ConversionConfig:!ConversionConfig,
|
|
92
92
|
* CustomerMatchConfig: !CustomerMatchConfig,
|
|
93
93
|
* CustomerMatchRecord: !CustomerMatchRecord,
|
|
94
94
|
* ReportQueryConfig:!ReportQueryConfig,
|
package/src/components/automl.js
CHANGED
|
@@ -17,15 +17,9 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
'use strict';
|
|
20
|
-
const {
|
|
21
|
-
const {JWT, Compute} = require('google-auth-library');
|
|
20
|
+
const { ClientOptions } = require('google-gax');
|
|
22
21
|
const automl = require('@google-cloud/automl');
|
|
23
22
|
const google = automl.protos.google;
|
|
24
|
-
const AuthClient = require('../apis/auth_client.js');
|
|
25
|
-
|
|
26
|
-
const API_SCOPES = Object.freeze([
|
|
27
|
-
'https://www.googleapis.com/auth/cloud-platform',
|
|
28
|
-
]);
|
|
29
23
|
|
|
30
24
|
/**
|
|
31
25
|
* For version `v1beta1`, BigQuery can be the source and destination.
|
|
@@ -40,46 +34,49 @@ const API_SCOPES = Object.freeze([
|
|
|
40
34
|
* @type {string}
|
|
41
35
|
*/
|
|
42
36
|
const API_VERSION = 'v1beta1';
|
|
43
|
-
const PredictionServiceClient = automl[API_VERSION]
|
|
37
|
+
const { PredictionServiceClient } = automl[API_VERSION];
|
|
44
38
|
|
|
45
39
|
/**
|
|
46
|
-
* AutoML Tables API
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* https://
|
|
51
|
-
* 2. 'get Operations' based on REST API, see:
|
|
52
|
-
* https://cloud.google.com/automl/docs/reference/rest/v1/projects.locations.operations/get
|
|
53
|
-
* https://cloud.google.com/automl-tables/docs/long-operations#get-operation
|
|
40
|
+
* AutoML Tables API class for:
|
|
41
|
+
* 1. start a batch predict job:
|
|
42
|
+
* @see https://cloud.google.com/nodejs/docs/reference/automl/latest/automl/v1beta1.predictionserviceclient#_google_cloud_automl_v1beta1_PredictionServiceClient_batchPredict_member_3_
|
|
43
|
+
* 2. get the status of an operation:
|
|
44
|
+
* @see https://cloud.google.com/nodejs/docs/reference/automl/latest/automl/v1beta1.predictionserviceclient#_google_cloud_automl_v1beta1_PredictionServiceClient_checkBatchPredictProgress_member_1_
|
|
54
45
|
*/
|
|
55
46
|
class AutoMl {
|
|
56
|
-
|
|
57
47
|
/**
|
|
58
48
|
* Initialize an instance.
|
|
59
|
-
* @param {
|
|
49
|
+
* @param {ClientOptions=} options
|
|
60
50
|
*/
|
|
61
51
|
constructor(options = {}) {
|
|
62
|
-
this.
|
|
52
|
+
this.client = new PredictionServiceClient(options);
|
|
63
53
|
}
|
|
64
54
|
|
|
65
55
|
/**
|
|
66
56
|
* Batch predicts based on Google Cloud Client Library.
|
|
67
|
-
* See https://googleapis.dev/nodejs/automl/latest/index.html
|
|
68
57
|
* @param {string} projectId
|
|
69
58
|
* @param {string} computeRegion
|
|
70
59
|
* @param {string} modelId
|
|
71
|
-
* @param {google.cloud.automl.
|
|
72
|
-
* @param {google.cloud.automl.
|
|
60
|
+
* @param {google.cloud.automl.v1beta1.IBatchPredictInputConfig} inputConfig
|
|
61
|
+
* @param {google.cloud.automl.v1beta1.IBatchPredictOutputConfig} outputConfig
|
|
73
62
|
* @return {Promise<string>} Predict operation name.
|
|
74
63
|
*/
|
|
75
|
-
async batchPredict(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
async batchPredict(
|
|
65
|
+
projectId,
|
|
66
|
+
computeRegion,
|
|
67
|
+
modelId,
|
|
68
|
+
inputConfig,
|
|
69
|
+
outputConfig
|
|
70
|
+
) {
|
|
71
|
+
const modelFullId = this.client.modelPath(
|
|
72
|
+
projectId,
|
|
73
|
+
computeRegion,
|
|
74
|
+
modelId
|
|
75
|
+
);
|
|
76
|
+
const responses = await this.client.batchPredict({
|
|
80
77
|
name: modelFullId,
|
|
81
|
-
inputConfig
|
|
82
|
-
outputConfig
|
|
78
|
+
inputConfig,
|
|
79
|
+
outputConfig,
|
|
83
80
|
});
|
|
84
81
|
const operation = responses[1];
|
|
85
82
|
console.log(`Operation name: ${operation.name}`);
|
|
@@ -87,37 +84,20 @@ class AutoMl {
|
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
/**
|
|
90
|
-
* Gets
|
|
91
|
-
* https://cloud.google.com/automl/docs/reference/rest/v1/projects.locations.operations/get
|
|
92
|
-
* https://cloud.google.com/automl-tables/docs/long-operations#get-operation
|
|
87
|
+
* Gets status of an operation.
|
|
93
88
|
* @param {string} operationName
|
|
94
|
-
* @return {Promise<
|
|
89
|
+
* @return {Promise<{{
|
|
90
|
+
* done: boolean,
|
|
91
|
+
* error: Error|undefined,
|
|
92
|
+
* metadata: OperationMetadata,
|
|
93
|
+
* name: string,
|
|
94
|
+
* }}>}
|
|
95
95
|
*/
|
|
96
96
|
async getOperation(operationName) {
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
method: 'GET',
|
|
101
|
-
headers,
|
|
102
|
-
url,
|
|
103
|
-
};
|
|
104
|
-
const response = await request(requestOptions);
|
|
105
|
-
return response.data;
|
|
97
|
+
const response = await this.client.checkBatchPredictProgress(operationName);
|
|
98
|
+
const { done, error, metadata, name } = response;
|
|
99
|
+
return { done, error, metadata, name };
|
|
106
100
|
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Gets authentication client of AutoML API.
|
|
110
|
-
* This API belongs to GCP, however it is not fully supported by Google Cloud
|
|
111
|
-
* Client Library. So we need to manage some functions on its REST API,
|
|
112
|
-
* in the way like we invoke other external APIs.
|
|
113
|
-
* @returns {(!JWT|!Compute)}
|
|
114
|
-
* @private
|
|
115
|
-
*/
|
|
116
|
-
getAuthClient_() {
|
|
117
|
-
/** @const {!AuthClient} */ const authClient = new AuthClient(API_SCOPES);
|
|
118
|
-
return authClient.getApplicationDefaultCredentials();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
101
|
}
|
|
122
102
|
|
|
123
103
|
exports.AutoMl = AutoMl;
|
|
@@ -30,11 +30,36 @@ const API_VERSION = 'v1';
|
|
|
30
30
|
* to get/pause/resume a job.
|
|
31
31
|
*/
|
|
32
32
|
class CloudScheduler {
|
|
33
|
-
constructor(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
constructor(env = process.env, options = {}) {
|
|
34
|
+
if (!options.authClient) {
|
|
35
|
+
/** @const {!AuthClient} */
|
|
36
|
+
const authClient = new AuthClient(API_SCOPES, env);
|
|
37
|
+
/**
|
|
38
|
+
* By default, `AuthClient` (getDefaultAuth()) will return an auth client
|
|
39
|
+
* based on the settings in ENV while the OAuth is the most preferred.
|
|
40
|
+
* This works for most of the external API clients (in the '../apis'
|
|
41
|
+
* folder), however this won't work in the Cloud Functions, as those OAuth
|
|
42
|
+
* token usually won't have enough permission to invoke Google Cloud API.
|
|
43
|
+
* Using the method `getApplicationDefaultCredentials` to force
|
|
44
|
+
* `AuthClient` return an ADC auth client, which will work in the Cloud.
|
|
45
|
+
*
|
|
46
|
+
* Cloud Scheduler API Client Library is used here as Cloud Client Library
|
|
47
|
+
* is still at beta stage. (For the difference, see
|
|
48
|
+
* https://cloud.google.com/apis/docs/client-libraries-explained)
|
|
49
|
+
* Eventually, when we migrate this to the cloud client library, which
|
|
50
|
+
* automatically takes ADC as the authentication method, the 'AuthClient'
|
|
51
|
+
* is not required here and can be removed.
|
|
52
|
+
*/
|
|
53
|
+
this.auth = authClient.getApplicationDefaultCredentials();
|
|
54
|
+
} else {
|
|
55
|
+
/**
|
|
56
|
+
* `authClient` can be consumed by cloud client library as the auth
|
|
57
|
+
* client. By passing this in, we can offer more flexible auth clients in
|
|
58
|
+
* test cases for API client library and cloud client library in future.
|
|
59
|
+
*/
|
|
60
|
+
this.auth = options.authClient;
|
|
61
|
+
}
|
|
62
|
+
this.projectId = env['GCP_PROJECT'];
|
|
38
63
|
this.instance = cloudscheduler({
|
|
39
64
|
version: API_VERSION,
|
|
40
65
|
auth: this.auth,
|
|
@@ -113,8 +138,8 @@ class CloudScheduler {
|
|
|
113
138
|
*/
|
|
114
139
|
async getJobs_(name, targetLocations = undefined) {
|
|
115
140
|
const regex = new RegExp(`/jobs/${name}$`);
|
|
116
|
-
const
|
|
117
|
-
|
|
141
|
+
const allJobs = await this.listJobs_(targetLocations);
|
|
142
|
+
const jobs = allJobs.filter((job) => regex.test(job));
|
|
118
143
|
if (jobs.length === 0) console.error(`Can not find job: ${name}`);
|
|
119
144
|
return jobs;
|
|
120
145
|
}
|
|
@@ -134,23 +159,10 @@ class CloudScheduler {
|
|
|
134
159
|
const projectId = await this.getProjectId_();
|
|
135
160
|
const requestPrefix = `projects/${projectId}/locations`;
|
|
136
161
|
const jobs = locations.map(async (location) => {
|
|
137
|
-
const request = {parent: `${requestPrefix}/${location}`};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return response.data.jobs.map((job) => job.name);
|
|
142
|
-
} catch (error) {
|
|
143
|
-
// Currently, listLocations always returns an array with one location.
|
|
144
|
-
// Not sure whether this will be changed or not in future. If one day
|
|
145
|
-
// the Cloud Scheduler let users to select a location for a job, then
|
|
146
|
-
// it may return multiple locations when listLocation, however the
|
|
147
|
-
// target job may exist in one of the locations. In this case, when we
|
|
148
|
-
// iterate the job with all possible locations to get the complete job
|
|
149
|
-
// path to operate, it will likely generate an error for those wrong
|
|
150
|
-
// location(s). So set the try-catch here to handle this situation.
|
|
151
|
-
console.error(error.message);
|
|
152
|
-
return [];
|
|
153
|
-
}
|
|
162
|
+
const request = { parent: `${requestPrefix}/${location}` };
|
|
163
|
+
const response = await this.instance.projects.locations.jobs.list(request);
|
|
164
|
+
if (!response.data.jobs) return [];
|
|
165
|
+
return response.data.jobs.map((job) => job.name);
|
|
154
166
|
});
|
|
155
167
|
// Waits for all jobs names and flattens nested job name arrays, however
|
|
156
168
|
// there is no 'flat' available in current Cloud Functions runtime.
|
package/src/components/utils.js
CHANGED
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
const winston = require('winston');
|
|
22
22
|
const {inspect} = require('util');
|
|
23
|
-
const {LoggingWinston} = require('@google-cloud/logging-winston');
|
|
24
|
-
const {CloudPlatformApis} = require('../apis/cloud_platform_apis.js');
|
|
23
|
+
const { LoggingWinston } = require('@google-cloud/logging-winston');
|
|
25
24
|
|
|
26
25
|
/**
|
|
27
26
|
* The result of a batch of data sent to target API. The batch here means the
|
|
@@ -498,37 +497,6 @@ const extractObject = (paths) => {
|
|
|
498
497
|
};
|
|
499
498
|
};
|
|
500
499
|
|
|
501
|
-
/**
|
|
502
|
-
* Checks whether the permissions are granted for current authentication.
|
|
503
|
-
* This function will be invoked during the deployment of a specific solution,
|
|
504
|
-
* e.g. Tentacles, to make sure the operator has the proper permissions to
|
|
505
|
-
* carry on. If the operator doesn't have enough permissions, it will exit with
|
|
506
|
-
* status code 1 to let the invoker (the Bash installation script) know that it
|
|
507
|
-
* doesn't pass.
|
|
508
|
-
* @param {!Array<string>} permissions Array of permissions to check.
|
|
509
|
-
* @param {string} projectId The Id of Cloud project.
|
|
510
|
-
* @return {!Promise<undefined>}
|
|
511
|
-
*/
|
|
512
|
-
const checkPermissions = (permissions,
|
|
513
|
-
projectId = process.env['GCP_PROJECT']) => {
|
|
514
|
-
const cloudPlatformApis = new CloudPlatformApis(projectId);
|
|
515
|
-
return cloudPlatformApis.testIamPermissions(permissions)
|
|
516
|
-
.then((grantedPermissions) => {
|
|
517
|
-
console.log(grantedPermissions);
|
|
518
|
-
grantedPermissions = grantedPermissions || [];
|
|
519
|
-
if (grantedPermissions.length < permissions.length) {
|
|
520
|
-
const missedPermissions = permissions.filter(
|
|
521
|
-
(permission) => grantedPermissions.indexOf(permission) === -1);
|
|
522
|
-
console.error(`[MISSED] ${missedPermissions.join(',')}.`);
|
|
523
|
-
process.exit(1);
|
|
524
|
-
}
|
|
525
|
-
})
|
|
526
|
-
.catch((error) => {
|
|
527
|
-
console.error(`[ERROR] ${error.message}`);
|
|
528
|
-
process.exit(1);
|
|
529
|
-
});
|
|
530
|
-
};
|
|
531
|
-
|
|
532
500
|
/**
|
|
533
501
|
* For more details, see:
|
|
534
502
|
* https://developers.google.com/google-ads/api/docs/rest/design/json-mappings
|
|
@@ -565,7 +533,6 @@ module.exports = {
|
|
|
565
533
|
replaceParameters,
|
|
566
534
|
getFilterFunction,
|
|
567
535
|
extractObject,
|
|
568
|
-
checkPermissions,
|
|
569
536
|
changeNamingFromSnakeToUpperCamel,
|
|
570
537
|
changeNamingFromSnakeToLowerCamel,
|
|
571
538
|
};
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
|
+
const { ClientOptions } = require('google-gax');
|
|
21
22
|
const {JobServiceClient} = require('@google-cloud/aiplatform');
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -29,7 +30,7 @@ class VertexAi {
|
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Initialize an instance.
|
|
32
|
-
* @param {
|
|
33
|
+
* @param {ClientOptions=} options
|
|
33
34
|
*/
|
|
34
35
|
constructor(options = {}) {
|
|
35
36
|
this.options = options;
|
|
@@ -105,9 +106,9 @@ class VertexAi {
|
|
|
105
106
|
* @private
|
|
106
107
|
*/
|
|
107
108
|
getJobServiceClient_(location) {
|
|
108
|
-
const clientOptions = {
|
|
109
|
+
const clientOptions = Object.assign({}, this.options, {
|
|
109
110
|
apiEndpoint: this.getServiceEndpoint_(location),
|
|
110
|
-
};
|
|
111
|
+
});
|
|
111
112
|
return new JobServiceClient(clientOptions);
|
|
112
113
|
}
|
|
113
114
|
}
|