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 takeIntersection(vpcZones, fcAllowedZones, nasZones) {
|
90 | const threeIntersection = _.filter(vpcZones, z => {
|
91 | return _.includes(fcAllowedZones, z.ZoneId) && _.includes(nasZones.map(zone => { return zone.ZoneId; }), z.ZoneId);
|
92 | });
|
93 | if (!_.isEmpty(threeIntersection)) {
|
94 | return threeIntersection;
|
95 | }
|
96 | return _.filter(vpcZones, z => {
|
97 | return _.includes(fcAllowedZones, z.ZoneId);
|
98 | });
|
99 | }
|
100 | function selectVSwitchZoneId(fcAllowedZones, vpcZones, nasZones) {
|
101 | return __awaiter(this, void 0, void 0, function* () {
|
102 | const allowedZones = takeIntersection(vpcZones, fcAllowedZones, nasZones);
|
103 | const sortedZones = _.sortBy(allowedZones, ['ZoneId']);
|
104 | return (_.head(sortedZones) || {}).ZoneId;
|
105 | });
|
106 | }
|
107 | function getFcAllowedZones() {
|
108 | return __awaiter(this, void 0, void 0, function* () {
|
109 | const fc = yield getFcClient();
|
110 | const fcRs = yield fc.getAccountSettings();
|
111 | const fcAllowedZones = fcRs.data.availableAZs;
|
112 | debug('fc allowed zones: %j', fcAllowedZones);
|
113 | if (_.isEqual(fcAllowedZones, [''])) {
|
114 | const profile = yield getProfile();
|
115 | 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}`));
|
116 | }
|
117 | return fcAllowedZones;
|
118 | });
|
119 | }
|
120 | function selectAllowedVSwitchZone(vpcClient, region) {
|
121 | return __awaiter(this, void 0, void 0, function* () {
|
122 | const nasClient = yield getNasPopClient();
|
123 | const fcAllowedZones = yield getFcAllowedZones();
|
124 | const vpcZones = yield describeVpcZones(vpcClient, region);
|
125 | const nasZones = yield require('./nas').describeNasZones(nasClient, region);
|
126 | const usedZoneId = yield selectVSwitchZoneId(fcAllowedZones, vpcZones, nasZones);
|
127 | if (!usedZoneId) {
|
128 | throw new Error('no availiable zone for vswitch');
|
129 | }
|
130 | debug('select allowed switch zone: ', usedZoneId);
|
131 | return usedZoneId;
|
132 | });
|
133 | }
|
134 | function describeVpcZones(vpcClient, region) {
|
135 | return __awaiter(this, void 0, void 0, function* () {
|
136 | const params = {
|
137 | 'RegionId': region
|
138 | };
|
139 | const zones = yield vpcClient.request('DescribeZones', params, requestOption);
|
140 | return zones.Zones.Zone;
|
141 | });
|
142 | }
|
143 | function convertToFcAllowedZones(vpcClient, region, vswitchIds) {
|
144 | return __awaiter(this, void 0, void 0, function* () {
|
145 | const fcAllowedZones = yield getFcAllowedZones();
|
146 | const fcZones = [];
|
147 | for (const vswitchId of vswitchIds) {
|
148 | const zoneId = yield getVSwitchZoneId(vpcClient, region, vswitchId);
|
149 | if (_.includes(fcAllowedZones, zoneId)) {
|
150 | fcZones.push({ zoneId, vswitchId });
|
151 | }
|
152 | }
|
153 | if (_.isEmpty(fcZones)) {
|
154 | throw new Error(`
|
155 | Only zoneId ${fcAllowedZones} of vswitch is allowed by VpcConfig.
|
156 | Check your vswitch zoneId please.`);
|
157 | }
|
158 | return fcZones;
|
159 | });
|
160 | }
|
161 | function convertZones(nasZones, zones, storageType = 'Performance') {
|
162 | const zoneId = nasZones.ZoneId;
|
163 | const vswitchId = zones.filter(f => { return f.zoneId === zoneId; });
|
164 | return {
|
165 | zoneId,
|
166 | vswitchId: _.head(vswitchId).vswitchId,
|
167 | storageType
|
168 | };
|
169 | }
|
170 | function processDifferentZones(nasZones, FcAllowVswitchId) {
|
171 | const performance = _.find(nasZones, nasZone => !_.isEmpty(nasZone.Performance.Protocol));
|
172 | if (!_.isEmpty(performance)) {
|
173 | return {
|
174 | zoneId: performance.ZoneId,
|
175 | vswitchId: FcAllowVswitchId,
|
176 | storageType: 'Performance'
|
177 | };
|
178 | }
|
179 | const capacity = _.find(nasZones, nasZone => !_.isEmpty(nasZone.Capacity.Protocol));
|
180 | if (!_.isEmpty(capacity)) {
|
181 | return {
|
182 | zoneId: capacity.ZoneId,
|
183 | vswitchId: FcAllowVswitchId,
|
184 | storageType: 'Capacity'
|
185 | };
|
186 | }
|
187 | return null;
|
188 | }
|
189 | function getAvailableVSwitchId(vpcClient, region, vswitchIds, nasZones) {
|
190 | return __awaiter(this, void 0, void 0, function* () {
|
191 | const fcZones = yield convertToFcAllowedZones(vpcClient, region, vswitchIds);
|
192 | const availableZones = fcZones.filter(fcZone => { return _.includes(nasZones.map(m => { return m.ZoneId; }), fcZone.zoneId); });
|
193 | const performances = [];
|
194 | const capacities = [];
|
195 | _.forEach(nasZones, nasZone => {
|
196 | if (_.includes(availableZones.map(z => z.zoneId), nasZone.ZoneId)) {
|
197 | if (!_.isEmpty(nasZone.Performance.Protocol)) {
|
198 | performances.push(nasZone);
|
199 | }
|
200 | if (!_.isEmpty(nasZone.Capacity.Protocol)) {
|
201 | capacities.push(nasZone);
|
202 | }
|
203 | }
|
204 | });
|
205 | if (!_.isEmpty(performances)) {
|
206 | return convertZones(_.head(performances), availableZones);
|
207 | }
|
208 | if (!_.isEmpty(capacities)) {
|
209 | const msg = `Region ${region} only supports capacity NAS. Do you want to create it automatically?`;
|
210 | const yes = yield promptForConfirmContinue(msg);
|
211 | if (yes) {
|
212 | return convertZones(_.head(capacities), availableZones, 'Capacity');
|
213 | }
|
214 | throw new Error(`No NAS service available under region ${region}.`);
|
215 | }
|
216 | return processDifferentZones(nasZones, _.head(fcZones).vswitchId);
|
217 | });
|
218 | }
|
219 | module.exports = {
|
220 | findVswitchExistByName,
|
221 | selectVSwitchZoneId,
|
222 | createVSwitch,
|
223 | createDefaultVSwitch,
|
224 | getAvailableVSwitchId
|
225 | };
|