1 | 'use strict';
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | return new (P || (P = Promise))(function (resolve, reject) {
|
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8 | });
|
9 | };
|
10 | const _ = require('lodash');
|
11 | const debug = require('debug')('fun:nas');
|
12 | const { red } = require('colors');
|
13 | const { getProfile } = require('./profile');
|
14 | const { getFcClient, getNasPopClient } = require('./client');
|
15 | const { promptForConfirmContinue } = require('./init/prompt');
|
16 | var requestOption = {
|
17 | method: 'POST'
|
18 | };
|
19 | function createDefaultVSwitch(vpcClient, region, vpcId, vswitchName) {
|
20 | return __awaiter(this, void 0, void 0, function* () {
|
21 | const vswitchZoneId = yield selectAllowedVSwitchZone(vpcClient, region);
|
22 | var vswitchId;
|
23 | try {
|
24 |
|
25 | vswitchId = yield createVSwitch(vpcClient, {
|
26 | region,
|
27 | vpcId,
|
28 | zoneId: vswitchZoneId,
|
29 | vswitchName: vswitchName
|
30 | });
|
31 | }
|
32 | catch (ex) {
|
33 | throw ex;
|
34 | }
|
35 | return vswitchId;
|
36 | });
|
37 | }
|
38 | function describeVSwitchAttributes(vpcClient, region, vswitchId) {
|
39 | return __awaiter(this, void 0, void 0, function* () {
|
40 | const params = {
|
41 | 'RegionId': region,
|
42 | 'VSwitchId': vswitchId
|
43 | };
|
44 | return yield vpcClient.request('DescribeVSwitchAttributes', params, requestOption);
|
45 | });
|
46 | }
|
47 | function getVSwitchZoneId(vpcClient, region, vswitchId) {
|
48 | return __awaiter(this, void 0, void 0, function* () {
|
49 | const describeRs = yield describeVSwitchAttributes(vpcClient, region, vswitchId);
|
50 | return (describeRs || {}).ZoneId;
|
51 | });
|
52 | }
|
53 | function getVSwitchName(vpcClient, region, vswitchId) {
|
54 | return __awaiter(this, void 0, void 0, function* () {
|
55 | const describeRs = yield describeVSwitchAttributes(vpcClient, region, vswitchId);
|
56 | return (describeRs || {}).VSwitchName;
|
57 | });
|
58 | }
|
59 | function findVswitchExistByName(vpcClient, region, vswitchIds, searchVSwtichName) {
|
60 | return __awaiter(this, void 0, void 0, function* () {
|
61 | if (!_.isEmpty(vswitchIds)) {
|
62 | for (let vswitchId of vswitchIds) {
|
63 | const vswitchName = yield getVSwitchName(vpcClient, region, vswitchId);
|
64 | if (_.isEqual(searchVSwtichName, vswitchName)) {
|
65 | debug('found default vswitchId: ' + vswitchId);
|
66 | return vswitchId;
|
67 | }
|
68 | }
|
69 | }
|
70 | debug('could not find %s from %j for region %s', searchVSwtichName, vswitchIds, region);
|
71 | return null;
|
72 | });
|
73 | }
|
74 | function createVSwitch(vpcClient, { region, vpcId, zoneId, vswitchName }) {
|
75 | return __awaiter(this, void 0, void 0, function* () {
|
76 | var params = {
|
77 | 'RegionId': region,
|
78 | 'VpcId': vpcId,
|
79 | 'ZoneId': zoneId,
|
80 | 'CidrBlock': '10.20.0.0/16',
|
81 | 'VSwitchName': vswitchName,
|
82 | 'Description': 'default vswitch created by fc fun'
|
83 | };
|
84 | debug('createVSwitch params is %j', params);
|
85 | const createRs = yield vpcClient.request('CreateVSwitch', params, requestOption);
|
86 | return createRs.VSwitchId;
|
87 | });
|
88 | }
|
89 | function selectVSwitchZoneId(fcAllowedZones, vpcZones, nasZones) {
|
90 | return __awaiter(this, void 0, void 0, function* () {
|
91 | const allowedZones = _.filter(vpcZones, z => {
|
92 | return _.includes(fcAllowedZones, z.ZoneId) && _.includes(nasZones.map(zone => { return zone.ZoneId; }), z.ZoneId);
|
93 | });
|
94 | const sortedZones = _.sortBy(allowedZones, ['ZoneId']);
|
95 | return (_.head(sortedZones) || {}).ZoneId;
|
96 | });
|
97 | }
|
98 | function getFcAllowedZones() {
|
99 | return __awaiter(this, void 0, void 0, function* () {
|
100 | const fc = yield getFcClient();
|
101 | const fcRs = yield fc.getAccountSettings();
|
102 | const fcAllowedZones = fcRs.data.availableAZs;
|
103 | debug('fc allowed zones: %j', fcAllowedZones);
|
104 | if (_.isEqual(fcAllowedZones, [''])) {
|
105 | const profile = yield getProfile();
|
106 | throw new Error(red(`No fc vswitch zones allowed, you may need login to fc console to apply for VPC feature: https://fc.console.aliyun.com/overview/${profile.defaultRegion}`));
|
107 | }
|
108 | return fcAllowedZones;
|
109 | });
|
110 | }
|
111 | function selectAllowedVSwitchZone(vpcClient, region) {
|
112 | return __awaiter(this, void 0, void 0, function* () {
|
113 | const nasClient = yield getNasPopClient();
|
114 | const fcAllowedZones = yield getFcAllowedZones();
|
115 | const vpcZones = yield describeVpcZones(vpcClient, region);
|
116 | const nasZones = yield require('./nas').describeNasZones(nasClient, region);
|
117 | const usedZoneId = yield selectVSwitchZoneId(fcAllowedZones, vpcZones, nasZones);
|
118 | if (!usedZoneId) {
|
119 | throw new Error('no availiable zone for vswitch');
|
120 | }
|
121 | debug('select allowed switch zone: ', usedZoneId);
|
122 | return usedZoneId;
|
123 | });
|
124 | }
|
125 | function describeVpcZones(vpcClient, region) {
|
126 | return __awaiter(this, void 0, void 0, function* () {
|
127 | const params = {
|
128 | 'RegionId': region
|
129 | };
|
130 | const zones = yield vpcClient.request('DescribeZones', params, requestOption);
|
131 | return zones.Zones.Zone;
|
132 | });
|
133 | }
|
134 | function convertToFcAllowedZoneMap(vpcClient, region, vswitchIds) {
|
135 | return __awaiter(this, void 0, void 0, function* () {
|
136 | const fcAllowedZones = yield getFcAllowedZones();
|
137 | const zoneMap = new Map();
|
138 | for (const vswitchId of vswitchIds) {
|
139 | const zoneId = yield getVSwitchZoneId(vpcClient, region, vswitchId);
|
140 | if (_.includes(fcAllowedZones, zoneId)) {
|
141 | zoneMap.set(zoneId, vswitchId);
|
142 | }
|
143 | }
|
144 | if (_.isEmpty(zoneMap)) {
|
145 | throw new Error(`
|
146 | Only zoneId ${fcAllowedZones} of vswitch is allowed by VpcConfig.
|
147 | Check your vswitch zoneId please.`);
|
148 | }
|
149 | return zoneMap;
|
150 | });
|
151 | }
|
152 | function convertZones(zones, zoneMap, storageType = 'Performance') {
|
153 | const zoneId = zones.ZoneId;
|
154 | return {
|
155 | zoneId,
|
156 | vswitchId: zoneMap.get(zoneId),
|
157 | storageType
|
158 | };
|
159 | }
|
160 | function processDifferentZones(nasZones, FcAllowVswitchId) {
|
161 | const performance = _.find(nasZones, nasZone => !_.isEmpty(nasZone.Performance.Protocol));
|
162 | if (!_.isEmpty(performance)) {
|
163 | return {
|
164 | zoneId: performance.ZoneId,
|
165 | vswitchId: FcAllowVswitchId,
|
166 | storageType: 'Performance'
|
167 | };
|
168 | }
|
169 | const capacity = _.find(nasZones, nasZone => !_.isEmpty(nasZone.Capacity.Protocol));
|
170 | if (!_.isEmpty(capacity)) {
|
171 | return {
|
172 | zoneId: capacity.ZoneId,
|
173 | vswitchId: FcAllowVswitchId,
|
174 | storageType: 'Capacity'
|
175 | };
|
176 | }
|
177 | return null;
|
178 | }
|
179 | function getAvailableVSwitchId(vpcClient, region, vswitchIds, nasZones) {
|
180 | return __awaiter(this, void 0, void 0, function* () {
|
181 | const zoneMap = yield convertToFcAllowedZoneMap(vpcClient, region, vswitchIds);
|
182 | for (const zoneId of zoneMap.keys()) {
|
183 | if (!_.includes(nasZones.map(m => { return m.ZoneId; }), zoneId)) {
|
184 | zoneMap.delete(zoneId);
|
185 | }
|
186 | }
|
187 | const performances = [];
|
188 | const capacities = [];
|
189 | _.forEach(nasZones, nasZone => {
|
190 | if (_.includes([...zoneMap.keys()], nasZone.ZoneId)) {
|
191 | if (!_.isEmpty(nasZone.Performance.Protocol)) {
|
192 | performances.push(nasZone);
|
193 | }
|
194 | if (!_.isEmpty(nasZone.Capacity.Protocol)) {
|
195 | capacities.push(nasZone);
|
196 | }
|
197 | }
|
198 | });
|
199 | if (!_.isEmpty(performances)) {
|
200 | return convertZones(_.head(performances), zoneMap);
|
201 | }
|
202 | if (!_.isEmpty(capacities)) {
|
203 | const msg = `Region ${region} only supports capacity NAS. Do you want to create it automatically?`;
|
204 | const yes = yield promptForConfirmContinue(msg);
|
205 | if (yes) {
|
206 | return convertZones(_.head(capacities), zoneMap, 'Capacity');
|
207 | }
|
208 | throw new Error(`No NAS service available under region ${region}.`);
|
209 | }
|
210 | return processDifferentZones(nasZones, _.head([...zoneMap.values()]));
|
211 | });
|
212 | }
|
213 | module.exports = {
|
214 | findVswitchExistByName,
|
215 | selectVSwitchZoneId,
|
216 | createVSwitch,
|
217 | createDefaultVSwitch,
|
218 | getAvailableVSwitchId
|
219 | };
|