Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aliyun/log/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from .metering_mode_response import GetLogStoreMeteringModeResponse, \
GetMetricStoreMeteringModeResponse, \
UpdateLogStoreMeteringModeResponse, UpdateMetricStoreMeteringModeResponse

from .object_response import PutObjectResponse, GetObjectResponse

from .store_view import StoreView, StoreViewStore
from .store_view_response import CreateStoreViewResponse, UpdateStoreViewResponse, DeleteStoreViewResponse, ListStoreViewsResponse, GetStoreViewResponse
Expand Down
6 changes: 3 additions & 3 deletions aliyun/log/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ def _getGMT():
logger.warning("failed to set locale time to C. skip it: {0}".format(ex))
return datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')

def sign_request(self, method, resource, params, headers, body):
def sign_request(self, method, resource, params, headers, body, compute_content_hash=True):
credentials = self.credentials_provider.get_credentials()
if credentials.get_security_token():
headers['x-acs-security-token'] = credentials.get_security_token()

headers['x-log-signaturemethod'] = 'hmac-sha1'
headers['Date'] = self._getGMT()

if body:
if body and compute_content_hash:
headers['Content-MD5'] = Util.cal_md5(body)
if not credentials.get_access_key_secret():
return six.b('')
Expand All @@ -92,7 +92,7 @@ def __init__(self, credentials_provider, region):
AuthBase.__init__(self, credentials_provider)
self._region = region

def sign_request(self, method, resource, params, headers, body):
def sign_request(self, method, resource, params, headers, body, compute_content_hash=True):
current_time = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
headers['Authorization'] = self._do_sign_request(method, resource, params, headers, body, current_time)

Expand Down
83 changes: 79 additions & 4 deletions aliyun/log/logclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
import requests
import six
import time
import zlib
from datetime import datetime
import logging
import re

from .store_view_response import ListStoreViewsResponse, CreateStoreViewResponse, UpdateStoreViewResponse, DeleteStoreViewResponse, GetStoreViewResponse
from .credentials import StaticCredentialsProvider
Expand Down Expand Up @@ -76,7 +76,8 @@
from .metering_mode_response import GetLogStoreMeteringModeResponse, \
GetMetricStoreMeteringModeResponse, UpdateLogStoreMeteringModeResponse, \
UpdateMetricStoreMeteringModeResponse
from .util import require_python3
from .object_response import PutObjectResponse, GetObjectResponse
from .util import require_python3, object_name_encode

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -310,7 +311,7 @@ def _sendRequest(self, method, url, params, body, headers, respons_body_type='js
'Request is failed. Http code is ' + str(resp_status) + exJson, requestId,
resp_status, resp_header, resp_body)

def _send(self, method, project, body, resource, params, headers, respons_body_type='json'):
def _send(self, method, project, body, resource, params, headers, respons_body_type='json', compute_content_hash=True):
if body:
headers['Content-Length'] = str(len(body))
else:
Expand All @@ -337,7 +338,7 @@ def _send(self, method, project, body, resource, params, headers, respons_body_t
params2 = copy(params)
if self._securityToken:
headers2["x-acs-security-token"] = self._securityToken
self._auth.sign_request(method, resource, params2, headers2, body)
self._auth.sign_request(method, resource, params2, headers2, body, compute_content_hash=compute_content_hash)
return self._sendRequest(method, url, params2, body, headers2, respons_body_type)
except LogException as ex:
last_err = ex
Expand Down Expand Up @@ -6511,3 +6512,77 @@ def delete_store_view(self, project_name, store_view_name):
resource = "/storeviews/" + store_view_name
(resp, header) = self._send("DELETE", project_name, None, resource, params, {})
return DeleteStoreViewResponse(header, resp)

def put_object(
self, project_name, logstore_name, object_name, content, headers=None
):
"""Put an object to the specified logstore.
Unsuccessful operation will cause an LogException.

:type project_name: string
:param project_name: the project name

:type logstore_name: string
:param logstore_name: the logstore name

:type object_name: string
:param object_name: the object name (only allow a-z A-Z 0-9 _ -)

:type content: bytes/string
:param content: the object content (can be empty)

:type headers: dict
:param headers: optional headers to send with the request.
- x-log-meta-* headers will be attached to the object as metadata, and returned in the response when getting the object
- Content-Type will be attached to the object as metadata, and returned in the response when getting the object
- Content-MD5 will be attached to the object as metadata, and returned in the response when getting the object

:return: PutObjectResponse

:raise: LogException
"""
encoded_object_name = object_name_encode(object_name)
if headers is None:
headers = {}
else:
headers = dict(headers)

if isinstance(content, six.text_type):
body = content.encode("utf-8")
elif isinstance(content, six.binary_type):
body = content
else:
raise LogException("InvalidParameter", "content must be bytes or string")

headers["x-log-bodyrawsize"] = str(len(body))
resource = "/logstores/" + logstore_name + "/objects/" + encoded_object_name

(resp, resp_header) = self._send(
"PUT", project_name, body, resource, {}, headers, compute_content_hash=False
)
return PutObjectResponse(resp_header, resp)

def get_object(self, project_name, logstore_name, object_name):
"""Get an object from the specified logstore.
Unsuccessful operation will cause an LogException.

:type project_name: string
:param project_name: the project name

:type logstore_name: string
:param logstore_name: the logstore name

:type object_name: string
:param object_name: the object name

:return: GetObjectResponse

:raise: LogException
"""
encoded_object_name = object_name_encode(object_name)
resource = "/logstores/" + logstore_name + "/objects/" + encoded_object_name

(resp, resp_header) = self._send(
"GET", project_name, None, resource, {}, {}, respons_body_type="raw"
)
return GetObjectResponse(resp_header, resp)
89 changes: 89 additions & 0 deletions aliyun/log/object_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python
# encoding: utf-8

# Copyright (C) Alibaba Cloud Computing
# All rights reserved.

from .logresponse import LogResponse
from .util import Util

__all__ = ['PutObjectResponse', 'GetObjectResponse']


class PutObjectResponse(LogResponse):
""" The response of the put_object API from log.

:type header: dict
:param header: PutObjectResponse HTTP response header

:type resp: string
:param resp: PutObjectResponse HTTP response body
"""

def __init__(self, header, resp=''):
LogResponse.__init__(self, header, resp)

def get_etag(self):
""" Get the ETag of the uploaded object.

:return: string, ETag value
"""
return Util.h_v_td(self.headers, 'ETag', None)

def log_print(self):
print('PutObjectResponse:')
print('headers:', self.get_all_headers())


class GetObjectResponse(LogResponse):
""" The response of the get_object API from log.

:type header: dict
:param header: GetObjectResponse HTTP response header

:type resp: bytes
:param resp: GetObjectResponse HTTP response body (object content)
"""

def __init__(self, header, resp):
LogResponse.__init__(self, header, resp)

def get_etag(self):
""" Get the ETag of the object.

:return: string, ETag value, may be None if not set
"""
return Util.h_v_td(self.headers, 'ETag', None)

def get_last_modified(self):
""" Get the last modified time of the object.

:return: string, last modified time, may be None if not set
"""
return Util.h_v_td(self.headers, 'Last-Modified', None)

def get_content_type(self):
""" Get the content type of the object.

:return: string, content type
"""
return Util.h_v_td(self.headers, 'Content-Type', '')

def get_headers(self):
""" Get all headers of the response.

:return: dict, all response headers
"""
return self.headers

def get_body(self):
""" Get the object content.

:return: bytes, object content
"""
return self.body

def log_print(self):
print('GetObjectResponse:')
print('headers:', self.get_all_headers())

12 changes: 11 additions & 1 deletion aliyun/log/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,14 @@ def wrapper(*args, **kwargs):
if not six.PY3:
raise RuntimeError("Function '{func_name}' requires Python 3 to run.".format(func_name=func.__name__))
return func(*args, **kwargs)
return wrapper
return wrapper


if six.PY2:
from urllib import quote as urlquote
else:
from urllib.parse import quote as urlquote
urlquote

def object_name_encode(object_name):
return urlquote(object_name)
2 changes: 1 addition & 1 deletion aliyun/log/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '0.9.37'
__version__ = '0.9.38'

import sys
OS_VERSION = str(sys.platform)
Expand Down
Loading
Loading