Class: Aspera::Api::CosNode

Inherits:
Node show all
Defined in:
lib/aspera/api/cos_node.rb

Constant Summary collapse

IBM_CLOUD_TOKEN_URL =
'https://iam.cloud.ibm.com/identity'
TOKEN_FIELD =
'delegated_refresh_token'
FASP_INFO_KEYS =
%w[ATSEndpoint AccessKey].freeze

Constants inherited from Node

Node::ACCESS_LEVELS, Node::HEADER_ACCEPT_VERSION, Node::HEADER_X_ASPERA_ACCESS_KEY, Node::HEADER_X_CACHE_CONTROL, Node::HEADER_X_NEXT_ITER_TOKEN, Node::HEADER_X_TOTAL_COUNT, Node::OPTIONS, Node::PATH_SEPARATOR

Constants inherited from Rest

Rest::MAX_ITEMS, Rest::MAX_PAGES

Instance Attribute Summary

Attributes inherited from Node

#app_info

Attributes inherited from Rest

#auth_params, #base_url, #headers

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Node

add_cache_control, add_private_key, add_public_key, #add_tspec_info, #base_spec, bearer_headers, bearer_token, decode_bearer_token, decode_scope, #entry_has_link_information, file_matcher, file_matcher_from_argument, #find_files, #list_files, #node_id_to_node, #process_folder_tree, #read_folder_content, #refreshed_transfer_token, #resolve_api_fid, #resolve_api_fid_paths, split_folder, token_scope, #transfer_spec_gen4, #transport_params

Methods inherited from Rest

basic_authorization, build_uri, #call, #cancel, #create, #delete, h_to_query_array, io_http_session, #lookup_by_name, #oauth, #params, parse_header, php_style, query_to_h, #read, remote_certificate_chain, start_http_session, #update

Constructor Details

#initialize(instance_id:, api_key:, endpoint:, bucket:, auth_url: IBM_CLOUD_TOKEN_URL) ⇒ CosNode

Returns a new instance of CosNode.



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
# File 'lib/aspera/api/cos_node.rb', line 35

def initialize(instance_id:, api_key:, endpoint:, bucket:, auth_url: IBM_CLOUD_TOKEN_URL)
  Aspera.assert_type(instance_id, String){'resource instance id (crn)'}
  Aspera.assert_type(endpoint, String){'endpoint'}
  endpoint = "https://#{endpoint}" unless endpoint.start_with?('http')
  @auth_url = auth_url
  @api_key = api_key
  s3_api = Aspera::Rest.new(
    base_url:       endpoint,
    not_auth_codes: %w[401 403], # error codes when not authorized
    headers:        {'ibm-service-instance-id' => instance_id},
    auth:           {
      type:          :oauth2,
      grant_method:  :generic,
      base_url:      @auth_url,
      grant_type:    'urn:ibm:params:oauth:grant-type:apikey',
      response_type: 'cloud_iam',
      apikey:        @api_key
    }
  )
  # read FASP connection information for bucket
  xml_result_text = s3_api.call(
    operation: 'GET',
    subpath:   bucket,
    headers:   {'Accept' => 'application/xml'},
    query:     {'faspConnectionInfo' => nil},
    ret:       :resp
  ).body
  ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
  Log.dump(:ats_info, ats_info)
  Aspera.assert_hash_all(ats_info, String, nil){'ats_info'}
  Aspera.assert((FASP_INFO_KEYS - ats_info.keys).empty?){'ats_info missing required keys'}
  Aspera.assert_hash_all(ats_info['AccessKey'], String, String){'ats_info'}
  @storage_credentials = {
    'type'  => 'token',
    'token' => {TOKEN_FIELD => nil}
  }
  super(
    base_url: ats_info['ATSEndpoint'],
    auth:     {
      type:     :basic,
      username: ats_info['AccessKey']['Id'],
      password: ats_info['AccessKey']['Secret']
    },
    add_tspec: {'tags'=>{Transfer::Spec::TAG_RESERVED=>{'node'=>{'storage_credentials'=>@storage_credentials}}}}
    )
  # update storage_credentials AND Rest params
  generate_token
end

Class Method Details

.parameters_from_svc_credentials(service_credentials, bucket_region) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/aspera/api/cos_node.rb', line 15

def parameters_from_svc_credentials(service_credentials, bucket_region)
  # check necessary contents
  Aspera.assert_type(service_credentials, Hash){'service_credentials'}
  Log.dump(:service_credentials, service_credentials)
  %w[apikey resource_instance_id endpoints].each do |field|
    Aspera.assert(service_credentials.key?(field)){"service_credentials must have a field: #{field}"}
  end
  # read endpoints from service provided in service credentials
  endpoints = Aspera::Rest.new(base_url: service_credentials['endpoints']).read('')
  Log.dump(:endpoints, endpoints)
  endpoint = endpoints.dig('service-endpoints', 'regional', bucket_region, 'public', bucket_region)
  raise "no such region: #{bucket_region}" if endpoint.nil?
  return {
    instance_id: service_credentials['resource_instance_id'],
    api_key:     service_credentials['apikey'],
    endpoint:    endpoint
  }
end

Instance Method Details

#generate_tokenObject

potentially call this if delegated token is expired



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/aspera/api/cos_node.rb', line 85

def generate_token
  # OAuth API to get delegated token
  delegated_oauth = OAuth::Factory.instance.create(
    base_url:     @auth_url,
    grant_method: :generic,
    token_field:  TOKEN_FIELD,
    grant_type:          'urn:ibm:params:oauth:grant-type:apikey',
    response_type:       'delegated_refresh_token',
    apikey:              @api_key,
    receiver_client_ids: 'aspera_ats'
  )
  # get delegated token to be placed in rest call header and in transfer tags
  @storage_credentials['token'][TOKEN_FIELD] = delegated_oauth.token
  headers['X-Aspera-Storage-Credentials'] = JSON.generate(@storage_credentials)
end