github.com/kyma-project/kyma-environment-broker@v0.0.1/testing/e2e/skr/kyma-environment-broker/client.js (about) 1 const axios = require('axios'); 2 const fs = require('fs'); 3 const {debug, getEnvOrThrow} = require('../utils'); 4 const {OAuthCredentials, OAuthToken} = require('../lib/oauth'); 5 6 const SCOPES = ['broker:write']; 7 const KYMA_SERVICE_ID = '47c9dcbf-ff30-448e-ab36-d3bad66ba281'; 8 const trialPlanID = '7d55d31d-35ae-4438-bf13-6ffdfa107d9f'; 9 10 class KEBConfig { 11 static fromEnv() { 12 return new KEBConfig( 13 getEnvOrThrow('KEB_HOST'), 14 OAuthCredentials.fromEnv('KEB_CLIENT_ID', 'KEB_CLIENT_SECRET'), 15 getEnvOrThrow('KEB_GLOBALACCOUNT_ID'), 16 getEnvOrThrow('KEB_SUBACCOUNT_ID'), 17 getEnvOrThrow('KEB_USER_ID'), 18 getEnvOrThrow('KEB_PLAN_ID'), 19 process.env.KEB_REGION, 20 process.env.KEB_PLATFORM_REGION, 21 process.env.KEB_TOKEN_URL, 22 ); 23 } 24 25 constructor(host, credentials, globalAccountID, subaccountID, userID, planID, region, platformRegion, tokenUrl) { 26 this.host = host; 27 this.credentials = credentials; 28 this.globalAccountID = globalAccountID; 29 this.subaccountID = subaccountID; 30 this.userID = userID; 31 this.planID = planID; 32 this.region = region; 33 this.platformRegion = platformRegion; 34 this.tokenUrl = tokenUrl; 35 } 36 } 37 38 class KEBClient { 39 constructor(config) { 40 let tokenUrl = `https://oauth2.${config.host}/oauth2/token`; 41 if (config.tokenUrl) { 42 tokenUrl = config.tokenUrl; 43 } 44 this.token = new OAuthToken(tokenUrl, config.credentials); 45 this.host = config.host; 46 this.globalAccountID = config.globalAccountID; 47 this.subaccountID = config.subaccountID; 48 this.userID = config.userID; 49 this.planID = config.planID; 50 this.region = config.region; 51 this.platformRegion = config.platformRegion; 52 } 53 54 async buildRequest(payload, endpoint, verb) { 55 const token = await this.token.getToken(SCOPES); 56 const platformRegion = this.getPlatformRegion(); 57 const url = `https://kyma-env-broker.${this.host}/oauth/${platformRegion}v2/${endpoint}`; 58 const headers = { 59 'X-Broker-API-Version': 2.14, 60 'Authorization': `Bearer ${token}`, 61 'Content-Type': 'application/json', 62 }; 63 const request = { 64 url: url, 65 method: verb, 66 headers: headers, 67 data: payload, 68 }; 69 return request; 70 } 71 72 async buildRequestWithoutToken(payload, endpoint, verb) { 73 const url = `https://kyma-env-broker.${this.host}/${endpoint}`; 74 const headers = { 75 'X-Broker-API-Version': 2.14, 76 'Content-Type': 'application/json', 77 }; 78 const request = { 79 url: url, 80 method: verb, 81 headers: headers, 82 data: payload, 83 }; 84 return request; 85 } 86 87 async callKEB(payload, endpoint, verb) { 88 const config = await this.buildRequest(payload, endpoint, verb); 89 90 try { 91 const resp = await axios.request(config); 92 if (resp.data.errors) { 93 throw new Error(resp.data); 94 } 95 return resp.data; 96 } catch (err) { 97 const msg = 'Error calling KEB'; 98 if (err.response) { 99 throw new Error(`${msg}: ${err.response.status} ${err.response.statusText}`); 100 } else { 101 throw new Error(`${msg}: ${err.toString()}`); 102 } 103 } 104 } 105 106 async callKEBWithoutToken(payload, endpoint, verb) { 107 const config = await this.buildRequestWithoutToken(payload, endpoint, verb); 108 try { 109 const resp = await axios.request(config); 110 if (!(resp.status === 403 || resp.status === 401)) { 111 throw new Error(`Unexpected status: ${resp.status}`); 112 } 113 } catch (err) { 114 const msg = 'Error calling KEB'; 115 if (err.response) { 116 if (!(err.response.status === 403 || err.response.status === 401)) { 117 throw new Error(`${msg}: ${err.response.status} ${err.response.statusText}`); 118 } 119 } else { 120 throw new Error(`${msg}: ${err.toString()}`); 121 } 122 } 123 } 124 125 async getSKR(instanceID) { 126 const endpoint = `service_instances/${instanceID}`; 127 try { 128 return await this.callKEB({}, endpoint, 'get'); 129 } catch (err) { 130 throw new Error(`error while getting SKR: ${err.toString()}`); 131 } 132 } 133 134 async getCatalog() { 135 const endpoint = `catalog`; 136 try { 137 return await this.callKEB({}, endpoint, 'get'); 138 } catch (err) { 139 throw new Error(`error while getting catalog: ${err.toString()}`); 140 } 141 } 142 143 buildPayload(name, instanceID, platformCreds, btpOperatorCreds, customParams) { 144 const payload = { 145 service_id: KYMA_SERVICE_ID, 146 plan_id: this.planID, 147 context: { 148 globalaccount_id: this.globalAccountID, 149 subaccount_id: this.subaccountID, 150 user_id: this.userID, 151 }, 152 parameters: { 153 name: name, 154 // Trial plan doesn't require region 155 ...(this.planID === trialPlanID ? {} : {region: this.region}), 156 ...customParams, 157 }, 158 }; 159 160 if (platformCreds && btpOperatorCreds) { 161 payload.context['sm_platform_credentials'] = { 162 credentials: { 163 basic: { 164 username: platformCreds.credentials.username, 165 password: platformCreds.credentials.password, 166 }, 167 }, 168 url: btpOperatorCreds.smURL, 169 }; 170 } else if (btpOperatorCreds) { 171 payload.context['sm_operator_credentials'] = { 172 clientid: btpOperatorCreds.clientid, 173 clientsecret: btpOperatorCreds.clientsecret, 174 sm_url: btpOperatorCreds.smURL, 175 url: btpOperatorCreds.url, 176 }; 177 } 178 return payload; 179 } 180 181 async provisionSKR(name, instanceID, platformCreds, btpOperatorCreds, customParams) { 182 const payload = this.buildPayload(name, instanceID, platformCreds, btpOperatorCreds, customParams); 183 184 const endpoint = `service_instances/${instanceID}`; 185 try { 186 return await this.callKEB(payload, endpoint, 'put'); 187 } catch (err) { 188 throw new Error(`error while provisioning SKR: ${err.toString()}`); 189 } 190 } 191 192 async updateSKR(instanceID, customParams, btpOperatorCreds, isMigration) { 193 const payload = { 194 service_id: KYMA_SERVICE_ID, 195 context: { 196 globalaccount_id: this.globalAccountID, 197 isMigration: isMigration, 198 }, 199 parameters: { 200 ...customParams, 201 }, 202 }; 203 204 if (btpOperatorCreds) { 205 payload.context['sm_operator_credentials'] = { 206 clientid: btpOperatorCreds.clientId, 207 clientsecret: btpOperatorCreds.clientSecret, 208 sm_url: btpOperatorCreds.smURL, 209 url: btpOperatorCreds.url, 210 }; 211 } 212 213 const endpoint = `service_instances/${instanceID}?accepts_incomplete=true`; 214 try { 215 return await this.callKEB(payload, endpoint, 'patch'); 216 } catch (err) { 217 throw new Error(`error while updating SKR: ${err.toString()}`); 218 } 219 } 220 221 async getOperation(instanceID, operationID) { 222 const endpoint = `service_instances/${instanceID}/last_operation?operation=${operationID}`; 223 try { 224 return await this.callKEB({}, endpoint, 'get'); 225 } catch (err) { 226 debug(err.toString()); 227 return new Error(`error while checking SKR State: ${err.toString()}`); 228 } 229 } 230 231 async deprovisionSKR(instanceID) { 232 const endpoint = `service_instances/${instanceID}?service_id=${KYMA_SERVICE_ID}&plan_id=${this.planID}`; 233 try { 234 return await this.callKEB(null, endpoint, 'delete'); 235 } catch (err) { 236 return new Error(`error while deprovisioning SKR: ${err.toString()}`); 237 } 238 } 239 240 async downloadKubeconfig(instanceID) { 241 const downloadUrl = `https://kyma-env-broker.${this.host}/kubeconfig/${instanceID}`; 242 debug(`Downloading kubeconfig from: ${downloadUrl}`); 243 return new Promise(async (resolve, reject) => { 244 const writeStream = fs 245 .createWriteStream('./shoot-kubeconfig.yaml') 246 .on('error', function(err) { 247 reject(err); 248 }) 249 .on('finish', function() { 250 writeStream.close(); 251 fs.readFile('./shoot-kubeconfig.yaml', 'utf8', (err, data) => { 252 fs.unlinkSync('./shoot-kubeconfig.yaml'); 253 resolve(data); 254 }); 255 }); 256 257 try { 258 const resp = await axios.request({ 259 method: 'get', 260 url: downloadUrl, 261 responseType: 'stream', 262 }); 263 if (resp.data.errors) { 264 throw new Error(resp.data); 265 } 266 resp.data.pipe(writeStream); 267 } catch (err) { 268 debug(err.data); 269 fs.unlinkSync('./shoot-kubeconfig.yaml'); 270 reject(err); 271 } 272 }); 273 } 274 275 getPlatformRegion() { 276 if (this.platformRegion && this.platformRegion != '') { 277 return `${this.platformRegion}/`; 278 } 279 return ''; 280 } 281 } 282 283 module.exports = { 284 KEBConfig, 285 KEBClient, 286 };