huangcm
2025-08-30 0269911b91ed7e03c24005924cc6423abf245fb8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
 
# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
 
import base64
import logging
import os
import subprocess
import tempfile
 
from oauth2client import service_account
 
_OPENID_SCOPE = 'openid'
 
class DashboardRestClient(object):
    """Instance of the Dashboard REST client.
 
    Attributes:
        post_cmd: String, The command-line string to post data to the dashboard,
                  e.g. 'wget <url> --post-file '
        service_json_path: String, The path to the service account keyfile
                           created from Google App Engine settings.
        auth_token: ServiceAccountCredentials object or None if not
                    initialized.
    """
 
    def __init__(self, post_cmd, service_json_path):
        self.post_cmd = post_cmd
        self.service_json_path = service_json_path
        self.auth_token = None
 
    def Initialize(self):
        """Initializes the client with an auth token and access token.
 
        Returns:
            True if the client is initialized successfully, False otherwise.
        """
        try:
            self.auth_token = service_account.ServiceAccountCredentials.from_json_keyfile_name(
                self.service_json_path, [_OPENID_SCOPE])
            self.auth_token.get_access_token()
        except IOError as e:
            logging.error("Error reading service json keyfile: %s", e)
            return False
        except (ValueError, KeyError) as e:
            logging.error("Invalid service json keyfile: %s", e)
            return False
        return True
 
 
    def _GetToken(self):
        """Gets an OAuth2 token using from a service account json keyfile.
 
        Uses the service account keyfile located at 'service_json_path', provided
        to the constructor, to request an OAuth2 token.
 
        Returns:
            String, an OAuth2 token using the service account credentials.
            None if authentication fails.
        """
        return str(self.auth_token.get_access_token().access_token)
 
    def AddAuthToken(self, post_message):
        """Add OAuth2 token to the dashboard message.
 
        Args:
            post_message: DashboardPostMessage, The data to post.
 
        Returns:
            True if successful, False otherwise
        """
        token = self._GetToken()
        if not token:
            return False
 
        post_message.access_token = token
 
    def PostData(self, post_message):
        """Post data to the dashboard database.
 
        Puts data into the dashboard database using its proto REST endpoint.
 
        Args:
            post_message: DashboardPostMessage, The data to post.
 
        Returns:
            True if successful, False otherwise
        """
        post_bytes = base64.b64encode(post_message.SerializeToString())
 
        with tempfile.NamedTemporaryFile(delete=False) as file:
            file.write(post_bytes)
        p = subprocess.Popen(
            self.post_cmd.format(path=file.name),
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)
        output, err = p.communicate()
        os.remove(file.name)
 
        if p.returncode or err:
            logging.error("Row insertion failed: %s", err)
            return False
        return True