UNPKG

ks3

Version:

本代码库为`金山云存储KS3`服务.主要提供`KS3 nodejs SDK`和`命令行工具`.

1,039 lines (883 loc) 26 kB
var auth = require('./../auth'); var config = require('./../../config'); var util = require('./../util'); var debug = require('debug')('ks3:bucket'); /** * 创建单个Bucket * * @param {Object} params * @param {String} params.Bucket * @param {String} params.ACL bucket权限设置 ['private' || 'public-read' || 'public-read-write' || 'authenticated-read'] * @param {String} params.Type bucket存储类型 ['NORMAL' || 'ARCHIVE'] * @param {String} params.Region bucket存储region ['BEIJING' || 'SHANGHAI' || 'HONGKONG' || 'GUANGZHOU' || 'RUSSIA' || 'SINGAPORE'] * @param {String} params.ProjectId 项目组id 非必填 * @param {String} params.VisitType 存储空间访问类型 非必填 */ function put(params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, '', 'PUT', params) if(params && params.ACL) { var acl = params.ACL; if(util.verifyAcl(acl) == null) { throw new Error('the illegal acl'); } var attr_Acl = 'x-'+config.prefix+'-acl'; req.headers[attr_Acl] = acl } if(params && params.VisitType){ if(['NORMAL', 'FREQUENTLIST'].indexOf(params.VisitType) > -1){ var visit_type = 'x-'+config.prefix+'-bucket-visit-type'; req.headers[visit_type] = params.VisitType }else{ throw new Error('the illegal visit type'); } } if(params && params.Type) { if(util.verifyBucketType(params.Type) == null) { throw new Error('the illegal bucket type'); } var attr_type = 'x-'+config.prefix+'-bucket-type'; req.headers[attr_type] = params.Type } var body = getCreateBucketConfiguration(params && params.Region); req.type = 'text/xml'; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获得创建bucket时用于设置region的请求体 * @param region */ function getCreateBucketConfiguration(region){ if(!region){ return null; } return '<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LocationConstraint>' + region + '</LocationConstraint></CreateBucketConfiguration>'; } /** * 获取bucket下的objects * * @param {Object} params * @param {String} params.Bucket // 非必传 * @param {String} params.Delimiter * @param {String} params.Marker * @param {String} params.MaxKeys // 默认为1000 * @param {String} params.Prefix * */ function listObjects (params, cb) { var queryString = []; if(typeof params === 'function') { cb = params; params = {}; } else { var opts = {} opts['prefix'] = params['Prefix'] || params.prefix || ''; opts['delimiter'] = params['Delimiter'] || params.delimiter || ''; opts['marker'] = params['Marker'] || params.marker || ''; opts['max-keys'] = params['MaxKeys'] || params['max-keys'] || 1000; opts['encoding-type'] = params['EncodingType'] || params['encoding-type'] || ''; if(params.Bucket){ opts.Bucket = params.Bucket; } if(params.Endpoint){ opts.Endpoint = params.Endpoint; } params = opts Object.keys(params).forEach(function(key) { if(key !== 'Bucket') { /** * 在之前的逻辑中,可以传递值为空的 delimiter * 但是现在后端修改逻辑了,禁止传递这样的delimiter */ if(!(key == 'delimiter' && params[key] == '')){ queryString.push(key + '=' + encodeURIComponent(params[key])); } } }); } var req = _getBucketRequestParams.call(this, '', 'GET', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); // 如果传入的params除了Bucket,还有其他的则,重新设置uri if(queryString.length > 0) { req.uri += (req.uri.indexOf('?') >= 0 ? '&' : '?'); req.uri += queryString.join('&'); } this.request(req, null, curAuth, cb); } /** * 获取bucket权限 * * @param {Object} params * @param {String} params.Bucket * */ function getACL(params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'acl', 'GET', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * 获取acl的类型 * * @param {*} params * @param {*} cb */ function getACLType(params, cb){ if (typeof params === 'function') { cb = params; params = {}; } params.DataType = 'json' this.bucket.getACL(params, function(err, body, res){ if (err) { cb(err, body, res, null) return } var type = 'private' var grant = body.AccessControlPolicy.AccessControlList.Grant const grantArray = Array.isArray(grant) ? grant : [grant] for(var grantee of grantArray) { if(grantee.Grantee.URI !== 'http://acs.ksyun.com/groups/global/AllUsers') { continue } if(grantee.Permission === 'WRITE'){ type = 'public-read-write' break } if(grantee.Permission === 'READ'){ type = 'public-read' } } cb(err, type, res, null) }) } /** * 修改bucket权限 * * @param {Object} params * @param {String} params.Bucket 非必填 * @param {String} params.ACL 'private || public-read || public-read-write || authenticated-read || bucket-owner-read || bucket-owner-full-control' // 必须 * @param {function} cb */ function putACL(params, cb) { var acl = params.ACL; if (!acl) { throw new Error('require the acl'); } if(util.verifyAcl(acl)==null){ throw new Error('the illegal acl'); } var req = _getBucketRequestParams.call(this, 'acl', 'PUT', params) var attr_Acl = 'x-'+config.prefix+'-acl'; req.headers[attr_Acl] = acl; var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * 获取location * * @param {Object} params * @param {String} params.Bucket 非必填 * @param {function} cb */ function getLocation(params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'location', 'GET', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * 获取日志信息 * * @param {Object} params * @param {String} params.Bucket 非必填 * @param {function} cb */ function getLogging(params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'logging', 'GET', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * 日志信息设置 * * @param {object} params * @param {String} params.Bucket 非必填 * @param {String} params.Logging { targetBucket, targetPrefix } // 可为空,若为空则为禁用日志 * @param {function} cb * @description * Logging: { targetBucket, targetPrefix } // 可为空,若为空则为禁用日志 */ function putLogging(params = {}, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'logging', 'PUT', params) var Logging = params.Logging || null; // 默认关闭 var p = `<BucketLoggingStatus xmlns="http://s3.amazonaws.com/doc/2006-03-01/"></BucketLoggingStatus>` if(Logging) { // 启用日志 const { targetBucket, targetPrefix} = Logging if (!targetBucket) throw new Error('Logging require the targetBucket') p = `<BucketLoggingStatus xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <LoggingEnabled> <TargetBucket>${targetBucket}</TargetBucket> <TargetPrefix>${targetPrefix}</TargetPrefix> </LoggingEnabled></BucketLoggingStatus>` } var body = p if(body){ req.type = 'text/xml'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 删除Bucket(单个) * * @param {object} params * @param {String} params.Bucket 非必填 * @param {function} cb * */ function del(params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, '', 'DELETE', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * 查看是否有权限操作bucket * * @param {object} params * @param {String} params.Bucket 非必填 * @param {function} cb * */ function headBucket(params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, '', 'HEAD', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * 获取当前bucket下的所有碎片 * * @param {object} params * @param {String} params.Bucket 非必填 * @param {String} params.Delimiter * @param {String} params.MaxUploads * @param {String} params.EncodingType * @param {String} params.UploadIdMarker * @param {String} params.KeyMarker * @param {String} params.Prefix * @param {function} cb * @description 具体详见: https://docs.ksyun.com/documents/927 * */ function listMultipartUploads (params, cb) { if(typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'uploads', 'GET', params) delete params.Bucket var opts = {} opts['delimiter'] = params.Delimiter || params.delimiter || '' opts['encoding-type'] = params.EncodingType || params['encoding-type'] || '' opts['max-uploads'] = params.MaxUploads || params['max-uploads'] || '' opts['upload-id-marker'] = params.UploadIdMarker || params['upload-id-marker'] || '' opts['key-marker'] = params.KeyMarker || params['key-marker'] || '' opts['prefix'] = params.Prefix || params.prefix || '' const queryStr = '&' + util.paramsEncode(opts) req.uri += queryStr var curAuth = auth.generateAuth(this.ak, this.sk, req); var body = null; this.request(req, body, curAuth, cb); } /** * put bucket cors * * @param {Object} params * @param {String} params.Bucket * @param {String | Array } params.Rules * @param {function} cb * @description Rules: { allowedMethod: '', allowedOrigin: [], allowedHeader: [], maxAgeSeconds: '', exposeHeader: '' } */ function putBucketCors (params, cb) { var rules = params.Rules if (!rules) { throw new Error('require the Rules') } if (!util.isArray(rules)) { rules = [rules] } rules = util.capitalize(rules) rules.forEach(rule => { // 'AllowedOrigin'、'AllowedMethod'[ every rules must be have] if (!rule.AllowedOrigin || !rule.AllowedOrigin.length) { throw new Error('require the AllowedOrigin') } if (!rule.AllowedMethod || !rule.AllowedMethod.length) { throw new Error('require the AllowedMethod') } }) var req = _getBucketRequestParams.call(this, 'cors', 'PUT', params) var body = util.convertToCORSXML(rules); if(body){ req.type = 'text/xml'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); // console.log('curAuth', curAuth) this.request(req, body, curAuth, cb); } /** * get bucket cors * * @param {Object} params * @param {String} params.Bucket * @param {function} cb */ function getBucketCors (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'cors', 'GET', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, '', curAuth, cb); } function deleteBucketCors (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } var req = _getBucketRequestParams.call(this, 'cors', 'DELETE', params) var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, '', curAuth, cb); } /** * 配置复制规则 * * @param {Object} params * @param {String} params.Bucket * @param {String} params.Rule * @param {function} cb * @description Rule: { Prefix: '', DeleteMarkerStatus: '', TargetBucket: '', HistoricalObjectReplication: ''} */ function putBucketReplicationConfiguration (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } if (!params.Rule) { throw new Error('require the Rule') } const Rule = util.capitalize(params.Rule) if (Rule.DeleteMarkerStatus) { // Enabled Disabled const flag = ['Enabled', 'Disabled'].indexOf(Rule.DeleteMarkerStatus) > -1 if (!flag) throw new Error("Rule's DeleteMarkerStatus value is only in 'Enabled' and 'Disabled, or null.' ") } if (Rule.HistoricalObjectReplication) { // Enabled Disabled const flag = ['Enabled', 'Disabled'].indexOf(Rule.DeleteMarkerStatus) > -1 if (!flag) throw new Error("Rule's HistoricalObjectReplication value is only in 'Enabled' and 'Disabled, or null.' ") } if (!Rule.TargetBucket) { throw new Error('require the targetBucket') } const req = _getBucketRequestParams.call(this, 'crr', 'PUT', params) var body = util.convertToReplicationXML(params.Rule) if(body){ req.type = 'text/xml'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取复制规则 * * @param {Object} params * @param {function} cb */ function getBucketReplicationConfiguration (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'crr', 'GET', params) var body = params; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 删除复制规则 * * @param {Object} params * @param {function} cb */ function deleteBucketReplicationConfiguration (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'crr', 'DELETE', params) var body = params; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 创建或者更新镜像回源规则 * * @param {Object} params * @param {String} params.Bucket * @param {String} params.Mirror * @param {function} cb */ function putBucketMirror (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const mirror = params.Mirror if (!mirror) throw new Error('require the Mirror') const req = _getBucketRequestParams.call(this, 'mirror', 'PUT', params) var body = JSON.stringify(mirror); if(body){ req.type = 'text/json'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取镜像回源规则 * @param {Object} params * @param {function} cb */ function getBucketMirror (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'mirror', 'GET', params) var body = params; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 删除镜像回源规则 * @param {Object} params * @param {function} cb */ function deleteBucketMirror (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'mirror', 'DELETE', params) var body = params; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 创建或者更新bucket policy * * @param {*} params * @param {Object} params * @param {Object} params.Bucket * @param {Object} params.Policy * @param {function} cb */ function putBucketPolicy (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } if (!params.Policy) throw new Error('require the Policy') const req = _getBucketRequestParams.call(this, 'policy', 'PUT', params) var body = JSON.stringify(params.Policy); console.log('put bucket policy: ', body) if(body){ req.type = 'text/json'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取BucketPolicy配置 * * @param {Object} params * @param {function} cb */ function getBucketPolicy (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'policy', 'GET', params) var body = params; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 删除空间的BucketPolicy配置 * * @param {Object} params * @param {function} cb */ function deleteBucketPolicy (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'policy', 'DELETE', params) var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 设置bucket生命周期策略 * * @param {Object} params * @param {String} params.Bucket * @param {String} params.Rules * @param {function} cb * @description * - Rules:规定的xml格式对等的json Array * - 详细文档请见https://docs.ksyun.com/documents/931 */ function putBucketLifecycle (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } if (!params.Rules) { throw new Error('require the Rules') } const rules = params.Rules if (!util.isArray(rules)) throw new Error('Rules must be Array') const rule = [] // in order to keep up with xml node when convert xml const fullParams = { lifecycleConfiguration: { rule } } rules.forEach(item => { util.checkLifecycleRule(item); if (item.id) { item.ID = item.id; delete item.id; } rule.push(item) }) const req = _getBucketRequestParams.call(this, 'lifecycle', 'PUT', params) var body = util.objToXml(fullParams); // console.log('json to xml : ', body) if(body){ req.type = 'text/xml'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取bucket的生命周期 * * @param {Object} params * @param {function} cb */ function getBucketLifecycle (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'lifecycle', 'GET', params) var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 删除生命周期配置 * * @param {Object} params * @param {function} cb */ function deleteBucketLifecycle (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'lifecycle', 'DELETE', params) var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 开通、关闭及设置Bucket回收站功能 * * @param {Object} params * @param {String} params.Status 必填,有效值:Enabled、Disabled。Enabled表示开启回收站,Disabled表示关闭回收站 * @param {Int} params.Days 非必填,指定Object进入回收站多少天后彻底删除。当不设置Days时,Object删除后将在回收站中永远保留,取值范围:1-365 * @param {function} cb */ function putBucketRetention (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } if(!params.Status){ throw new Error('require the Status') } if(params.Status !== 'Enabled' && params.Status !== 'Disabled'){ throw new Error('Status must be Enabled or Disabled') } if(params.Days && !Number.isInteger(params.Days)){ throw new Error('Days must be Integer') } if(params.Days && (params.Days < 1 || params.Days > 365)){ throw new Error('Days must be between 1 and 365') } const req = _getBucketRequestParams.call(this, 'retention', 'PUT', params) const fullParams = { RetentionConfiguration: { rule: { Status: params.Status, Days: params.Days } } } var body = util.objToXml(fullParams);; if(body){ req.type = 'text/xml'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取Bucket回收站配置规则 * * @param {Object} params * @param {function} * @param {function} cb */ function getBucketRetention (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'retention', 'GET', params) var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取Bucket回收站中Object列表 * * @param {Object} params * @param {String} params.Bucket 必填,指定Bucket * @param {String} params.Prefix 非必填,指定前缀 * @param {String} params.Marker 非必填,指定Marker * @param {Int} params.MaxKeys 非必填,指定最大返回数量 * @param {function} cb */ function listBucketRetention (params, cb) { var queryString = []; if(typeof params === 'function') { cb = params; params = {}; } else { var opts = {} opts['prefix'] = params['Prefix'] || params.prefix || ''; opts['marker'] = params['Marker'] || params.marker || ''; opts['delimiter'] = params['delimiter'] || params.delimiter || ''; opts['max-keys'] = params['MaxKeys'] || params['max-keys'] || 1000; if(params.Bucket){ opts.Bucket = params.Bucket; } params = opts Object.keys(params).forEach(function(key) { if(key !== 'Bucket') { /** * 在之前的逻辑中,可以传递值为空的 delimiter * 但是现在后端修改逻辑了,禁止传递这样的delimiter */ if(params[key] !== ''){ queryString.push(key + '=' + encodeURIComponent(params[key])); } } }); } const req = _getBucketRequestParams.call(this, 'recycle', 'GET', params) // 如果传入的params除了Bucket,还有其他的则,重新设置uri if(queryString.length > 0) { req.uri += (req.uri.indexOf('?') >= 0 ? '&' : '?'); req.uri += queryString.join('&'); } var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 设置Bucket加密 * * @param {Object} params * @param {String} params.Bucket 必填,指定Bucket * @param {String} params.Encryption 非必填,指定加密方式,默认AES256,目前仅支持AES256 * @param {function} cb */ function putBucketEncryption (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'encryption', 'PUT', params) const encryption = params.Encryption || 'AES256'; const fullParams = { ServerSideEncryptionConfiguration: { rule: { ApplyServerSideEncryptionByDefault: { SSEAlgorithm: encryption } } } } var body = util.objToXml(fullParams); if(body){ req.type = 'text/xml'; req.headers['Content-MD5'] = auth.hmacMd5(body) } var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 获取Bucket加密 * * @param {Object} params * @param {function} * @param {function} cb */ function getBucketEncryption (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'encryption', 'GET', params) var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } /** * 删除Bucket加密 * * @param {Object} params * @param {function} cb */ function deleteBucketEncryption (params, cb) { if (typeof params === 'function') { cb = params; params = {}; } const req = _getBucketRequestParams.call(this, 'encryption', 'DELETE', params) var body = null; var curAuth = auth.generateAuth(this.ak, this.sk, req); this.request(req, body, curAuth, cb); } function _getBucketRequestParams (subres, method, params) { var bucketName = params.Bucket || this.bucketName || ''; if(!bucketName) { throw new Error('require the bucketName'); } else if(!util.verifyBucket(bucketName)) { throw new Error('the illegal bucketName'); } let endpoint = params.Endpoint || this.endpoint var queryStr = params.ProjectId ? '?projectId=' + params.ProjectId : '' var resource = '/' + (subres ? `?${subres}` : ''); var date = (new Date()).toUTCString(); var uri = config.protocol + '://' + bucketName + '.' + endpoint + resource + queryStr // 是否是自定义域名 if (this.domainMode) { uri = config.protocol + '://' + endpoint + resource + queryStr } const type = params.Type || params.type const dataType = params.DataType || params.dataType var req = { method: method, date: date, uri, resource: '/' + bucketName + resource, type: type || '', headers: params.headers || {}, dataType: dataType || '' } return req; } module.exports = { put: put, get: listObjects, getACL: getACL, getACLType: getACLType, putACL: putACL, getLocation: getLocation, getLogging: getLogging, putLogging: putLogging, del: del, head: headBucket, listMultipartUploads, getBucketCors, putBucketCors, deleteBucketCors, putBucketReplicationConfiguration, getBucketReplicationConfiguration, deleteBucketReplicationConfiguration, getBucketMirror, deleteBucketMirror, putBucketMirror, getBucketPolicy, deleteBucketPolicy, putBucketPolicy, getBucketLifecycle, deleteBucketLifecycle, putBucketLifecycle, putBucketRetention, getBucketRetention, listBucketRetention, putBucketEncryption, getBucketEncryption, deleteBucketEncryption }