2222const conductor = require ( './conductor' )
2323const fs = require ( 'fs' )
2424const openwhisk = require ( 'openwhisk' )
25+ const ibmcloudUtils = require ( './ibmcloud-utils' )
2526const os = require ( 'os' )
2627const path = require ( 'path' )
2728
29+ const NS_TYPE_CF = 'CF'
30+ const NS_TYPE_IAM = 'IAM'
31+
2832// return enhanced openwhisk client capable of deploying compositions
2933module . exports = function ( options , basic , bearer ) {
3034 // try to extract apihost and key first from whisk property file file and then from process.env
3135 let apihost
3236 let apiversion
3337 let apikey
3438 let ignorecerts
35- let namespace = '_'
39+ let namespace = ibmcloudUtils . getNamespaceId ( )
3640 let token
3741 let authHandler
3842
@@ -49,31 +53,77 @@ module.exports = function (options, basic, bearer) {
4953 apiversion = parts [ 1 ]
5054 } else if ( parts [ 0 ] === 'AUTH' ) {
5155 apikey = parts [ 1 ]
52- } else if ( parts [ 0 ] === 'NAMESPACE' ) {
53- namespace = parts [ 1 ]
5456 } else if ( parts [ 0 ] === 'APIGW_ACCESS_TOKEN' ) {
5557 token = parts [ 1 ]
5658 }
5759 }
5860 }
59- } catch ( error ) { }
61+ } catch ( error ) { }
6062
6163 if ( process . env . __OW_API_HOST ) apihost = process . env . __OW_API_HOST
6264 if ( process . env . __OW_API_KEY ) apikey = process . env . __OW_API_KEY
6365 if ( process . env . __OW_NAMESPACE ) namespace = process . env . __OW_NAMESPACE
6466 if ( process . env . __OW_IGNORE_CERTS ) ignorecerts = process . env . __OW_IGNORE_CERTS
6567 if ( process . env . __OW_APIGW_TOKEN ) token = process . env . __OW_APIGW_TOKEN
6668
67- if ( bearer || ( ! basic && namespace !== '_' ) ) {
68- // switch from basic auth to bearer token
69+ // check whether there is a CLI argument that overrides the API key retrieved from the config or env
70+ if ( options && options . api_key ) apikey = options . api_key
71+
72+ // retrieve the namespace type
73+ // we need to apply different authentication strategies for CF and IAM
74+ const namespaceType = ibmcloudUtils . getNamespaceType ( )
75+
76+ //
77+ // check for IAM-based namespaces, first
78+ if ( namespaceType === NS_TYPE_IAM ) {
79+ // for authentication, we'll use the user IAM access token
80+ const iamToken = ibmcloudUtils . getIamAuthHeader ( )
81+
82+ // define an appropriate authentication handler for IAM
6983 authHandler = {
7084 getAuthHeader : ( ) => {
71- return Promise . resolve ( `Bearer ${ token } ` )
85+ // use bearer token for IAM authentication
86+ return Promise . resolve ( iamToken )
7287 }
7388 }
89+
90+ // ignore the API key value, in case of an IAM-based namespace
91+ apikey = undefined
92+
93+ //
94+ // in case of CF-based namespaces, the user can opt-in for using bearer token authentication instead of using the default basic authentication
95+ } else if ( namespaceType === NS_TYPE_CF ) {
96+ if ( bearer && ! basic ) {
97+ // switch from basic auth to bearer token
98+ authHandler = {
99+ getAuthHeader : ( ) => {
100+ return Promise . resolve ( `Bearer ${ token } ` )
101+ }
102+ }
103+ } else if ( apikey ) {
104+ // use basic auth
105+ authHandler = {
106+ getAuthHeader : ( ) => {
107+ const apiKeyBase64 = Buffer . from ( apikey ) . toString ( 'base64' )
108+ return Promise . resolve ( `Basic ${ apiKeyBase64 } ` )
109+ }
110+ }
111+ }
112+ }
113+
114+ const namespaceDisplayName = namespace || '_'
115+
116+ console . log ( `deploying to ${ namespaceType } -based namespace '${ namespaceDisplayName } ' ...` )
117+
118+ if ( ! authHandler ) {
119+ throw new Error (
120+ `Failed to determine the authentication strategy for the ${ namespaceType } -based namespace '${ namespaceDisplayName } '`
121+ )
74122 }
75123
76- const wsk = openwhisk ( Object . assign ( { apihost, apiversion, api_key : apikey , auth_handler : authHandler , namespace, ignore_certs : ignorecerts } , options ) )
124+ const wsk = openwhisk (
125+ Object . assign ( { apihost, apiversion, auth_handler : authHandler , namespace, ignore_certs : ignorecerts } , options )
126+ )
77127 wsk . compositions = new Compositions ( wsk )
78128 return wsk
79129}
@@ -90,9 +140,17 @@ class Compositions {
90140 return Object . assign ( { } , action , httpOptions )
91141 }
92142
93- const actions = ( composition . actions || [ ] ) . concat ( conductor . generate ( composition , debug , kind , timeout , memory , logs ) ) . map ( addHttpOptions )
94- return actions . reduce ( ( promise , action ) => promise . then ( ( ) => overwrite && this . actions . delete ( action ) . catch ( ( ) => { } ) )
95- . then ( ( ) => this . actions . create ( action ) ) , Promise . resolve ( ) )
143+ const actions = ( composition . actions || [ ] )
144+ . concat ( conductor . generate ( composition , debug , kind , timeout , memory , logs ) )
145+ . map ( addHttpOptions )
146+ return actions
147+ . reduce (
148+ ( promise , action ) =>
149+ promise
150+ . then ( ( ) => overwrite && this . actions . delete ( action ) . catch ( ( ) => { } ) )
151+ . then ( ( ) => this . actions . create ( action ) ) ,
152+ Promise . resolve ( )
153+ )
96154 . then ( ( ) => actions )
97155 }
98156}
0 commit comments