Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69b92a64bc | ||
|
|
f84ecd7212 | ||
|
|
5b6bb90119 | ||
|
|
d5637065c2 | ||
|
|
6d322c3cc2 | ||
|
|
e0ba340ca1 | ||
|
|
79ec7af773 | ||
|
|
752a3329be | ||
|
|
36a246504f | ||
|
|
b2a4b41023 | ||
|
|
852c943f99 | ||
|
|
96e33ca765 | ||
|
|
bae80ec847 | ||
|
|
ce55788a26 | ||
|
|
17e128099e | ||
|
|
17f391ffbd | ||
|
|
23bf5f58f6 | ||
|
|
b36616f28a | ||
|
|
5e266a4461 | ||
|
|
0dd199d5f8 | ||
|
|
0f020e96a7 | ||
|
|
0dcba31636 | ||
|
|
04221eb03a | ||
|
|
c12039d354 | ||
|
|
c5dcc547a9 | ||
|
|
5c3e10f9df | ||
|
|
e1848da829 | ||
|
|
a4ae065d8b | ||
|
|
8e0ffd72fa | ||
|
|
fafe697af5 | ||
|
|
2cf319175d | ||
|
|
643cb9775d | ||
|
|
66085e49c5 | ||
|
|
fd85d65aeb | ||
|
|
24a3573f73 | ||
|
|
048fc6d89d | ||
|
|
bf20f4efd4 | ||
|
|
2fd05a2b54 | ||
|
|
03ce50c255 | ||
|
|
171f552571 | ||
|
|
1843907b42 | ||
|
|
d88a6f2359 | ||
|
|
d273bc937e | ||
|
|
6777d2f0d8 | ||
|
|
3d2506639d | ||
|
|
a9806bd94e | ||
|
|
783642f083 | ||
|
|
2a7fec03d7 | ||
|
|
aed18cccfa | ||
|
|
0f12ee6649 | ||
|
|
fbc727a66e | ||
|
|
897fa2a631 | ||
|
|
43a428592e | ||
|
|
c3796b478f | ||
|
|
e12f60516b | ||
|
|
84fe322c96 | ||
|
|
84263b08dd | ||
|
|
895e069326 | ||
|
|
da4c940055 | ||
|
|
f9e608c06c | ||
|
|
15e8c12508 | ||
|
|
1e543b1e6f | ||
|
|
00739082f2 | ||
|
|
aacf23f57b | ||
|
|
ca037b42ef | ||
|
|
96300e1e99 | ||
|
|
721fbe24b8 | ||
|
|
b20a6fe858 | ||
|
|
658bd6a131 | ||
|
|
be5c9ef85e | ||
|
|
5cc6f7a3c6 | ||
|
|
5fdd26306a | ||
|
|
0e74d8873f | ||
|
|
3f8e9290de | ||
|
|
034dde5e1d | ||
|
|
d0e274cd5f | ||
|
|
b3de18bbda | ||
|
|
e02ac30cde | ||
|
|
49b444cfc8 | ||
|
|
1ab9055fc5 | ||
|
|
fd8e542467 | ||
|
|
7699978f39 | ||
|
|
902db15c17 | ||
|
|
49bd59df62 | ||
|
|
b7e44f436c | ||
|
|
aa26928716 | ||
|
|
8509a520cf | ||
|
|
0037634b70 | ||
|
|
6dfab50871 | ||
|
|
fcc46cdb1a | ||
|
|
06c4fae9c2 | ||
|
|
8b18a65303 | ||
|
|
e4ad1dde54 | ||
|
|
a2b82501aa | ||
|
|
ad0c4cbbd1 | ||
|
|
1a638c16bf | ||
|
|
7dd9fc79c2 | ||
|
|
d492c5e4a8 | ||
|
|
c2a14e5f79 | ||
|
|
c888c068b4 | ||
|
|
7b0bacc990 | ||
|
|
4d66c40c07 | ||
|
|
8a86130fe6 | ||
|
|
b7db4a5f00 | ||
|
|
f3b9869d4f | ||
|
|
0801f84b10 | ||
|
|
9dd091f982 | ||
|
|
190967a889 | ||
|
|
510254922b | ||
|
|
91da6199b3 | ||
|
|
9374a60e2a | ||
|
|
0e1817947e | ||
|
|
870ad47cbc | ||
|
|
4304c56685 | ||
|
|
b7dfee506f | ||
|
|
022b414766 | ||
|
|
05143c78c0 | ||
|
|
04ed3a22ef | ||
|
|
d3f0513224 | ||
|
|
d5efa608bc | ||
|
|
040d2187cb | ||
|
|
2d254ae238 | ||
|
|
82861f2130 | ||
|
|
e0270e6925 | ||
|
|
dc2180af03 | ||
|
|
d240b06c5c | ||
|
|
2434d2d157 | ||
|
|
c631fb141e | ||
|
|
4e27a35e4e | ||
|
|
1b458ab2df | ||
|
|
082e98c01a | ||
|
|
c6d1f84c57 | ||
|
|
c3b9e8532f | ||
|
|
4194973884 | ||
|
|
57a47d7794 | ||
|
|
953930bc42 | ||
|
|
35d78b4db0 | ||
|
|
b8a8b8bace | ||
|
|
e09d03f1ef | ||
|
|
dd2f328f45 | ||
|
|
b3895be44a | ||
|
|
7516f46903 | ||
|
|
3c7327ed57 | ||
|
|
8e1c027038 | ||
|
|
f8fe33039c | ||
|
|
bf6ea3cd51 | ||
|
|
e3aeeea51f | ||
|
|
1fba40289e | ||
|
|
b32c18a349 | ||
|
|
9fc6bdd5a3 | ||
|
|
755fd11f1a | ||
|
|
82984673aa |
2
.gitignore
vendored
@@ -48,4 +48,4 @@ secrets.json
|
||||
|
||||
qmi-cloud-tf-modules/
|
||||
*.pfx
|
||||
|
||||
/photos/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Stage 1:
|
||||
FROM node:13.8-alpine AS sources
|
||||
FROM node:15.12.0-alpine AS sources
|
||||
|
||||
RUN apk --no-cache add yarn
|
||||
RUN apk --no-cache add yarn git
|
||||
|
||||
WORKDIR /var/www/app
|
||||
|
||||
@@ -12,7 +12,7 @@ ADD ./qmi-cloud-common ./qmi-cloud-common
|
||||
RUN yarn install --production
|
||||
|
||||
# Stage 2:
|
||||
FROM node:13.8-alpine AS production
|
||||
FROM node:15.12.0-alpine AS production
|
||||
WORKDIR /var/www/app
|
||||
COPY --from=sources /var/www/app/node_modules ./node_modules
|
||||
COPY --from=sources /var/www/app/package.json ./package.json
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# QMI Cloud
|
||||
|
||||
[](https://gitlab.com/qmi/qmi-cloud/-/commits/master)
|
||||
|
||||
## Pre-requisites
|
||||
- Docker
|
||||
- Docker-Compose
|
||||
|
||||
BIN
dist/qmi-cloud/assets/user1.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 713 KiB After Width: | Height: | Size: 699 KiB |
BIN
dist/qmi-cloud/fa-brands-400.a06da7f0950f9dd366fc.woff2
vendored
Normal file
BIN
dist/qmi-cloud/fa-brands-400.ec3cfddedb8bebd2d7a3.woff
vendored
Normal file
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!--
|
||||
Font Awesome Free 5.14.0 by @fontawesome - https://fontawesome.com
|
||||
Font Awesome Free 5.13.0 by @fontawesome - https://fontawesome.com
|
||||
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
-->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
|
||||
<metadata>
|
||||
Created by FontForge 20200314 at Wed Jul 15 11:59:40 2020
|
||||
Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020
|
||||
By Robert Madole
|
||||
Copyright (c) Font Awesome
|
||||
</metadata>
|
||||
@@ -20,7 +20,7 @@ Copyright (c) Font Awesome
|
||||
panose-1="2 0 5 3 0 0 0 0 0 0"
|
||||
ascent="448"
|
||||
descent="-64"
|
||||
bbox="-0.0663408 -64.0662 640.004 448.1"
|
||||
bbox="-0.0663408 -64.0662 640.01 448.1"
|
||||
underline-thickness="25"
|
||||
underline-position="-50"
|
||||
unicode-range="U+0020-F5C8"
|
||||
@@ -50,7 +50,7 @@ s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 192c0 -19.8818 -16.
|
||||
<glyph glyph-name="flag" unicode=""
|
||||
d="M336.174 368c35.4668 0 73.0195 12.6914 108.922 28.1797c31.6406 13.6514 66.9043 -9.65723 66.9043 -44.1162v-239.919c0 -16.1953 -8.1543 -31.3057 -21.7129 -40.1631c-26.5762 -17.3643 -70.0693 -39.9814 -128.548 -39.9814c-68.6084 0 -112.781 32 -161.913 32
|
||||
c-56.5674 0 -89.957 -11.2803 -127.826 -28.5566v-83.4434c0 -8.83691 -7.16309 -16 -16 -16h-16c-8.83691 0 -16 7.16309 -16 16v406.438c-14.3428 8.2998 -24 23.7979 -24 41.5615c0 27.5693 23.2422 49.71 51.2012 47.8965
|
||||
c22.9658 -1.49023 41.8662 -19.4717 44.4805 -42.3379c0.213867 -1.83398 0.308594 -3.65918 0.308594 -5.5498c0 -5.30273 -0.860352 -10.4053 -2.4502 -15.1768c22.418 8.68555 49.4199 15.168 80.7207 15.168c68.6084 0 112.781 -32 161.913 -32zM464 112v240
|
||||
c22.9658 -1.49023 41.8662 -19.4717 44.4805 -42.3379c0.177734 -1.52441 0.321289 -4.00781 0.321289 -5.54199c0 -4.30176 -1.10352 -11.1035 -2.46289 -15.1846c22.418 8.68555 49.4199 15.168 80.7207 15.168c68.6084 0 112.781 -32 161.913 -32zM464 112v240
|
||||
c-31.5059 -14.6338 -84.5547 -32 -127.826 -32c-59.9111 0 -101.968 32 -161.913 32c-41.4365 0 -80.4766 -16.5879 -102.261 -32v-232c31.4473 14.5967 84.4648 24 127.826 24c59.9111 0 101.968 -32 161.913 -32c41.4365 0 80.4775 16.5879 102.261 32z" />
|
||||
<glyph glyph-name="bookmark" unicode="" horiz-adv-x="384"
|
||||
d="M336 448c26.5098 0 48 -21.4902 48 -48v-464l-192 112l-192 -112v464c0 26.5098 21.4902 48 48 48h288zM336 19.5703v374.434c0 3.31348 -2.68555 5.99609 -6 5.99609h-276c-3.31152 0 -6 -2.68848 -6 -6v-374.43l144 84z" />
|
||||
@@ -77,17 +77,17 @@ c0 -110.569 89.4678 -200 200 -200zM363.244 247.2c0 -67.0518 -72.4209 -68.084 -72
|
||||
c17.5615 9.84473 28.3242 16.541 28.3242 29.5791c0 17.2461 -21.999 28.6934 -39.7842 28.6934c-23.1885 0 -33.8936 -10.9775 -48.9424 -29.9697c-4.05664 -5.11914 -11.46 -6.07031 -16.666 -2.12402l-27.8232 21.0986
|
||||
c-5.10742 3.87207 -6.25098 11.0654 -2.64453 16.3633c23.627 34.6934 53.7217 54.1846 100.575 54.1846c49.0713 0 101.45 -38.3037 101.45 -88.7998zM298 80c0 -23.1592 -18.8408 -42 -42 -42s-42 18.8408 -42 42s18.8408 42 42 42s42 -18.8408 42 -42z" />
|
||||
<glyph glyph-name="eye" unicode="" horiz-adv-x="576"
|
||||
d="M288 304c0.114258 0 0.240234 -0.0175781 0.354492 -0.0175781c61.6543 0 111.71 -50.0557 111.71 -111.71s-50.0557 -111.71 -111.71 -111.71s-111.71 50.0557 -111.71 111.71c0 10.7422 1.51953 21.1328 4.35547 30.9678
|
||||
c7.95898 -4.52637 17.2129 -7.17188 27 -7.24023c30.9072 0 56 25.0928 56 56c-0.0683594 9.78711 -2.71387 19.041 -7.24023 27c9.88379 3.07617 20.3896 4.83008 31.2402 5zM572.52 206.6c2.21387 -4.37793 3.46094 -9.38965 3.46094 -14.626
|
||||
c0 -5.2373 -1.24707 -10.1855 -3.46094 -14.5635c-54.1992 -105.771 -161.59 -177.41 -284.52 -177.41s-230.29 71.5898 -284.52 177.4c-2.21387 4.37793 -3.46094 9.38965 -3.46094 14.626c0 5.2373 1.24707 10.1855 3.46094 14.5635
|
||||
c54.1992 105.771 161.59 177.41 284.52 177.41s230.29 -71.5898 284.52 -177.4zM288 48c98.6602 0 189.1 55 237.93 144c-48.8398 89 -139.27 144 -237.93 144s-189.09 -55 -237.93 -144c48.8398 -89 139.279 -144 237.93 -144z" />
|
||||
d="M288 304c0.0927734 0 0.244141 0.000976562 0.336914 0.000976562c61.6641 0 111.71 -50.0469 111.71 -111.711c0 -61.6631 -50.0459 -111.71 -111.71 -111.71s-111.71 50.0469 -111.71 111.71c0 8.71289 1.95898 22.5781 4.37305 30.9502
|
||||
c6.93066 -3.94141 19.0273 -7.18457 27 -7.24023c30.9121 0 56 25.0879 56 56c-0.0556641 7.97266 -3.29883 20.0693 -7.24023 27c8.42383 2.62207 22.4189 4.8623 31.2402 5zM572.52 206.6c1.9209 -3.79883 3.47949 -10.3379 3.47949 -14.5947
|
||||
s-1.55859 -10.7959 -3.47949 -14.5947c-54.1992 -105.771 -161.59 -177.41 -284.52 -177.41s-230.29 71.5898 -284.52 177.4c-1.9209 3.79883 -3.47949 10.3379 -3.47949 14.5947s1.55859 10.7959 3.47949 14.5947c54.1992 105.771 161.59 177.41 284.52 177.41
|
||||
s230.29 -71.5898 284.52 -177.4zM288 48c98.6602 0 189.1 55 237.93 144c-48.8398 89 -139.27 144 -237.93 144s-189.09 -55 -237.93 -144c48.8398 -89 139.279 -144 237.93 -144z" />
|
||||
<glyph glyph-name="eye-slash" unicode="" horiz-adv-x="640"
|
||||
d="M634 -23c3.66895 -2.93262 6.00391 -7.45117 6.00391 -12.5088c0 -3.7832 -1.31543 -7.26074 -3.51367 -10.001l-10 -12.4902c-2.93359 -3.66309 -7.44824 -5.99414 -12.502 -5.99414c-3.77637 0 -7.25 1.31152 -9.98828 3.50391l-598 467.49
|
||||
c-3.66895 2.93262 -6.00391 7.45117 -6.00391 12.5088c0 3.7832 1.31543 7.26074 3.51367 10.001l10 12.4902c2.93359 3.66309 7.44824 5.99414 12.502 5.99414c3.77637 0 7.25 -1.31152 9.98828 -3.50391zM296.79 301.53c7.51172 1.60254 15.2266 2.45508 23.21 2.46973
|
||||
c60.4805 0 109.36 -47.9102 111.58 -107.85zM343.21 82.46c-7.51367 -1.59375 -15.2285 -2.44336 -23.21 -2.45996c-60.4697 0 -109.35 47.9102 -111.58 107.84zM320 336c-19.8799 0 -39.2803 -2.7998 -58.2197 -7.09961l-46.4102 36.29
|
||||
c32.9199 11.8096 67.9297 18.8096 104.63 18.8096c122.93 0 230.29 -71.5898 284.57 -177.4c2.21289 -4.37793 3.45996 -9.38965 3.45996 -14.626c0 -5.2373 -1.24707 -10.1855 -3.45996 -14.5635c-14.1924 -27.5625 -31.9229 -52.6689 -52.9004 -75.1104l-37.7402 29.5
|
||||
c17.2305 18.0527 31.9385 38.1318 44 60.2002c-48.8398 89 -139.279 144 -237.93 144zM320 48c19.8896 0 39.2803 2.7998 58.2197 7.08984l46.4102 -36.2803c-32.9199 -11.7598 -67.9297 -18.8096 -104.63 -18.8096c-122.92 0 -230.28 71.5898 -284.51 177.4
|
||||
c-2.21387 4.37793 -3.46094 9.38965 -3.46094 14.626c0 5.2373 1.24707 10.1855 3.46094 14.5635c14.1885 27.5586 31.916 52.6621 52.8896 75.1006l37.7402 -29.5c-17.249 -18.0469 -31.9727 -38.1221 -44.0498 -60.1904c48.8496 -89 139.279 -144 237.93 -144z" />
|
||||
d="M634 -23c3.31738 -2.65137 6.00977 -8.25098 6.00977 -12.498c0 -3.10449 -1.57715 -7.58984 -3.51953 -10.0117l-10 -12.4902c-2.65234 -3.31152 -8.24707 -6 -12.4902 -6c-3.09961 0 -7.58008 1.57227 -10 3.50977l-598 467.49
|
||||
c-3.31738 2.65137 -6.00977 8.25098 -6.00977 12.498c0 3.10449 1.57715 7.58984 3.51953 10.0117l10 12.4902c2.65234 3.31152 8.24707 6 12.4902 6c3.09961 0 7.58008 -1.57227 10 -3.50977zM296.79 301.53c6.33496 1.35059 16.7324 2.45801 23.21 2.46973
|
||||
c60.4805 0 109.36 -47.9102 111.58 -107.85zM343.21 82.46c-6.33496 -1.34375 -16.7334 -2.44629 -23.21 -2.45996c-60.4697 0 -109.35 47.9102 -111.58 107.84zM320 336c-19.8799 0 -39.2803 -2.7998 -58.2197 -7.09961l-46.4102 36.29
|
||||
c32.9199 11.8096 67.9297 18.8096 104.63 18.8096c122.93 0 230.29 -71.5898 284.57 -177.4c1.91992 -3.79883 3.47949 -10.3379 3.47949 -14.5947s-1.55957 -10.7959 -3.47949 -14.5947c-11.7197 -22.7598 -35.4189 -56.4092 -52.9004 -75.1104l-37.7402 29.5
|
||||
c14.333 15.0156 34.0449 41.9854 44 60.2002c-48.8398 89 -139.279 144 -237.93 144zM320 48c19.8896 0 39.2803 2.7998 58.2197 7.08984l46.4102 -36.2803c-32.9199 -11.7598 -67.9297 -18.8096 -104.63 -18.8096c-122.92 0 -230.28 71.5898 -284.51 177.4
|
||||
c-1.9209 3.79883 -3.47949 10.3379 -3.47949 14.5947s1.55859 10.7959 3.47949 14.5947c11.7168 22.7568 35.4111 56.4014 52.8896 75.1006l37.7402 -29.5c-14.3467 -15.0107 -34.0811 -41.9756 -44.0498 -60.1904c48.8496 -89 139.279 -144 237.93 -144z" />
|
||||
<glyph glyph-name="calendar-alt" unicode="" horiz-adv-x="448"
|
||||
d="M148 160h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM256 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
||||
c6.59961 0 12 -5.40039 12 -12v-40zM352 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM256 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40
|
||||
@@ -131,47 +131,47 @@ d="M527.9 416c26.5996 0 48.0996 -21.5 48.0996 -48v-352c0 -26.5 -21.5 -48 -48.099
|
||||
h-467.801zM521.9 16c3.2998 0 6 2.7002 6 6v170h-479.801v-170c0 -3.2998 2.7002 -6 6 -6h467.801zM192 116v-40c0 -6.59961 -5.40039 -12 -12 -12h-72c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h72c6.59961 0 12 -5.40039 12 -12zM384 116v-40
|
||||
c0 -6.59961 -5.40039 -12 -12 -12h-136c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h136c6.59961 0 12 -5.40039 12 -12z" />
|
||||
<glyph glyph-name="hdd" unicode="" horiz-adv-x="576"
|
||||
d="M567.403 212.358c5.59668 -8.04688 8.59668 -17.6113 8.59668 -27.4121v-136.946c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v136.946c0 10.167 3.19531 19.6465 8.59668 27.4121l105.08 151.053
|
||||
c8.67383 12.4678 23.0791 20.5889 39.4043 20.5889h269.838c16.3252 0 30.7305 -8.12109 39.4043 -20.5889zM153.081 336l-77.9131 -112h425.664l-77.9131 112h-269.838zM528 48v128h-480v-128h480zM496 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32
|
||||
s14.3271 32 32 32s32 -14.3271 32 -32zM400 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32z" />
|
||||
d="M567.403 212.358c5.59668 -8.04688 8.59668 -17.6113 8.59668 -27.4121v-136.946c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v136.946c0 8.30957 3.85156 20.5898 8.59668 27.4121l105.08 151.053
|
||||
c7.90625 11.3652 25.5596 20.5889 39.4033 20.5889h0.000976562h269.838h0.000976562c13.8438 0 31.4971 -9.22363 39.4033 -20.5889zM153.081 336l-77.9131 -112h425.664l-77.9131 112h-269.838zM528 48v128h-480v-128h480zM496 112c0 -17.6729 -14.3271 -32 -32 -32
|
||||
s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32zM400 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32z" />
|
||||
<glyph glyph-name="hand-point-right" unicode=""
|
||||
d="M428.8 310.4c45.0996 0 83.2002 -38.1016 83.2002 -83.2002c0 -45.6162 -37.7646 -83.2002 -83.2002 -83.2002h-35.6475c-1.71387 -7.70605 -4.43555 -15.2051 -7.92969 -22.0645c2.50586 -22.0059 -3.50293 -44.9775 -15.9844 -62.791
|
||||
d="M428.8 310.4c45.0996 0 83.2002 -38.1016 83.2002 -83.2002c0 -45.6162 -37.7646 -83.2002 -83.2002 -83.2002h-35.6475c-1.41602 -6.36719 -4.96875 -16.252 -7.92969 -22.0645c2.50586 -22.0059 -3.50293 -44.9775 -15.9844 -62.791
|
||||
c-1.14062 -52.4863 -37.3984 -91.1445 -99.9404 -91.1445h-21.2988c-60.0635 0 -98.5117 40 -127.2 40h-2.67871c-5.74707 -4.95215 -13.5361 -8 -22.1201 -8h-64c-17.6729 0 -32 12.8936 -32 28.7998v230.4c0 15.9062 14.3271 28.7998 32 28.7998h64.001
|
||||
c8.58398 0 16.373 -3.04785 22.1201 -8h2.67871c6.96387 0 14.8623 6.19336 30.1816 23.6689l0.128906 0.148438l0.130859 0.145508c8.85645 9.93652 18.1162 20.8398 25.8506 33.2529c18.7051 30.2471 30.3936 78.7842 75.707 78.7842c56.9277 0 92 -35.2861 92 -83.2002
|
||||
c0 -0.0283203 0 0.0361328 0 0.0078125c0 -7.66602 -0.748047 -15.1582 -2.17578 -22.4072h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994
|
||||
c0 26.4004 -20.625 35.2002 -44 35.2002c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
|
||||
v-0.0839844c0 -6.21777 -0.974609 -16.2148 -2.17578 -22.3154h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994c0 26.4004 -20.625 35.2002 -44 35.2002
|
||||
c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
|
||||
c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
||||
<glyph glyph-name="hand-point-left" unicode=""
|
||||
d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529
|
||||
l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64
|
||||
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-3.49414 6.85938 -6.21582 14.3584 -7.92969 22.0645h-35.6465
|
||||
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-2.96094 5.8125 -6.51367 15.6973 -7.92969 22.0645h-35.6465
|
||||
c-45.4355 0 -83.2002 37.584 -83.2002 83.2002zM48 227.2c0 -18.9756 16.2246 -35.2002 35.2002 -35.2002h91.0244c-12.8369 -14.6689 -14.415 -42.8252 4.9502 -61.0498c-11.2256 -19.6465 -1.68652 -45.624 12.9248 -53.625
|
||||
c-6.52246 -39.1279 10.0771 -61.3252 50.6016 -61.3252h21.2988c45.4912 0 77.21 35.9131 120 39.6768v176.752c-25.2393 2.96289 -42.9658 21.2227 -59.0752 39.5967c-11.2744 12.6494 -21.7246 25.2998 -30.7988 39.875
|
||||
c-14.4814 23.3877 -26.1318 56.0996 -34.9258 56.0996c-23.375 0 -44 -8.7998 -44 -35.2002c0 -35.2002 26.3994 -53.0752 26.3994 -70.3994h-158.399c-18.4248 0 -35.2002 -16.5 -35.2002 -35.2002zM448 88c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24
|
||||
s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||
<glyph glyph-name="hand-point-up" unicode="" horiz-adv-x="448"
|
||||
d="M105.6 364.8c0 45.0996 38.1016 83.2002 83.2002 83.2002c45.6162 0 83.2002 -37.7646 83.2002 -83.2002v-35.6465c7.70605 -1.71387 15.2051 -4.43555 22.0645 -7.92969c22.0059 2.50684 44.9775 -3.50293 62.791 -15.9844
|
||||
d="M105.6 364.8c0 45.0996 38.1016 83.2002 83.2002 83.2002c45.6162 0 83.2002 -37.7646 83.2002 -83.2002v-35.6465c6.36719 -1.41602 16.252 -4.96875 22.0645 -7.92969c22.0059 2.50684 44.9775 -3.50293 62.791 -15.9844
|
||||
c52.4863 -1.14062 91.1445 -37.3984 91.1445 -99.9404v-21.2988c0 -60.0635 -40 -98.5117 -40 -127.2v-2.67871c4.95215 -5.74707 8 -13.5361 8 -22.1201v-64c0 -17.6729 -12.8936 -32 -28.7998 -32h-230.4c-15.9062 0 -28.7998 14.3271 -28.7998 32v64
|
||||
c0 8.58398 3.04785 16.373 8 22.1201v2.67871c0 6.96387 -6.19336 14.8623 -23.6689 30.1816l-0.148438 0.128906l-0.145508 0.130859c-9.93652 8.85645 -20.8398 18.1162 -33.2529 25.8506c-30.2471 18.7051 -78.7842 30.3936 -78.7842 75.707
|
||||
c0 56.9277 35.2861 92 83.2002 92c0.0283203 0 -0.0361328 0 -0.0078125 0c7.66602 0 15.1582 -0.748047 22.4072 -2.17578v86.1768zM224 364.8c0 18.9756 -16.2246 35.2002 -35.2002 35.2002c-18.7002 0 -35.2002 -16.7754 -35.2002 -35.2002v-158.399
|
||||
c-17.3242 0 -35.1992 26.3994 -70.3994 26.3994c-26.4004 0 -35.2002 -20.625 -35.2002 -44c0 -8.79395 32.7119 -20.4443 56.0996 -34.9258c14.5752 -9.07422 27.2256 -19.5244 39.875 -30.7988c18.374 -16.1094 36.6328 -33.8359 39.5967 -59.0752h176.753
|
||||
c3.7627 42.79 39.6758 74.5088 39.6758 120v21.2988c0 40.5244 -22.1973 57.124 -61.3252 50.6006c-8.00098 14.6113 -33.9785 24.1514 -53.625 12.9248c-18.2246 19.3652 -46.3809 17.7871 -61.0498 4.9502v91.0254zM352 24c-13.2549 0 -24 -10.7451 -24 -24
|
||||
s10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||
c0 56.9277 35.2861 92 83.2002 92h0.0839844c6.21777 0 16.2148 -0.974609 22.3154 -2.17578v86.1768zM224 364.8c0 18.9756 -16.2246 35.2002 -35.2002 35.2002c-18.7002 0 -35.2002 -16.7754 -35.2002 -35.2002v-158.399c-17.3242 0 -35.1992 26.3994 -70.3994 26.3994
|
||||
c-26.4004 0 -35.2002 -20.625 -35.2002 -44c0 -8.79395 32.7119 -20.4443 56.0996 -34.9258c14.5752 -9.07422 27.2256 -19.5244 39.875 -30.7988c18.374 -16.1094 36.6328 -33.8359 39.5967 -59.0752h176.753c3.7627 42.79 39.6758 74.5088 39.6758 120v21.2988
|
||||
c0 40.5244 -22.1973 57.124 -61.3252 50.6006c-8.00098 14.6113 -33.9785 24.1514 -53.625 12.9248c-18.2246 19.3652 -46.3809 17.7871 -61.0498 4.9502v91.0254zM352 24c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||
<glyph glyph-name="hand-point-down" unicode="" horiz-adv-x="448"
|
||||
d="M188.8 -64c-45.0986 0 -83.2002 38.1006 -83.2002 83.2002v86.1758c-6.91016 -1.3623 -14.374 -2.17578 -22.3994 -2.17578c-47.9141 0 -83.2002 35.0723 -83.2002 92c0 45.3135 48.5371 57.002 78.7852 75.707c12.4121 7.73438 23.3154 16.9951 33.2529 25.8506
|
||||
l0.145508 0.130859l0.148438 0.128906c17.4746 15.3213 23.668 23.2197 23.668 30.1836v2.67871c-4.95215 5.74707 -8 13.5361 -8 22.1201v64c0 17.6729 12.8936 32 28.7998 32h230.4c15.9062 0 28.7998 -14.3271 28.7998 -32v-64.001
|
||||
c0 -8.58398 -3.04785 -16.373 -8 -22.1201v-2.67871c0 -28.6885 40 -67.1367 40 -127.2v-21.2988c0 -62.542 -38.6582 -98.8008 -91.1445 -99.9404c-17.8135 -12.4814 -40.7852 -18.4922 -62.791 -15.9844c-6.85938 -3.49414 -14.3584 -6.21582 -22.0645 -7.92969v-35.6465
|
||||
c0 -8.58398 -3.04785 -16.373 -8 -22.1201v-2.67871c0 -28.6885 40 -67.1367 40 -127.2v-21.2988c0 -62.542 -38.6582 -98.8008 -91.1445 -99.9404c-17.8135 -12.4814 -40.7852 -18.4922 -62.791 -15.9844c-5.8125 -2.96094 -15.6973 -6.51367 -22.0645 -7.92969v-35.6465
|
||||
c0 -45.4355 -37.584 -83.2002 -83.2002 -83.2002zM188.8 -16c18.9756 0 35.2002 16.2246 35.2002 35.2002v91.0244c14.6689 -12.8369 42.8252 -14.415 61.0498 4.9502c19.6465 -11.2256 45.624 -1.68652 53.625 12.9248c39.1279 -6.52246 61.3252 10.0771 61.3252 50.6016
|
||||
v21.2988c0 45.4912 -35.9131 77.21 -39.6768 120h-176.752c-2.96289 -25.2393 -21.2227 -42.9658 -39.5967 -59.0752c-12.6494 -11.2744 -25.2998 -21.7246 -39.875 -30.7988c-23.3877 -14.4814 -56.0996 -26.1318 -56.0996 -34.9258c0 -23.375 8.7998 -44 35.2002 -44
|
||||
c35.2002 0 53.0752 26.3994 70.3994 26.3994v-158.399c0 -18.4248 16.5 -35.2002 35.2002 -35.2002zM328 384c0 -13.2549 10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24z" />
|
||||
<glyph glyph-name="copy" unicode="" horiz-adv-x="448"
|
||||
d="M433.941 382.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-80v-48c0 -26.5098 -21.4902 -48 -48 -48h-224c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h80v48c0 26.5098 21.4902 48 48 48
|
||||
h172.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM266 -16c3.31152 0 6 2.68848 6 6v42h-96c-26.5098 0 -48 21.4902 -48 48v224h-74c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM394 80c3.31152 0 6 2.68848 6 6v202h-88
|
||||
c-13.2549 0 -24 10.7451 -24 24v88h-106c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM400 336v9.63184c0 1.65527 -0.670898 3.15723 -1.75684 4.24316l-48.3682 48.3682c-1.12598 1.125 -2.65234 1.75684 -4.24316 1.75684h-9.63184v-64h64z" />
|
||||
d="M433.941 382.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-80v-48c0 -26.5098 -21.4902 -48 -48 -48h-224c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h80v48c0 26.5098 21.4902 48 48 48
|
||||
h172.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM266 -16c3.31152 0 6 2.68848 6 6v42h-96c-26.5098 0 -48 21.4902 -48 48v224h-74c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM394 80c3.31152 0 6 2.68848 6 6v202h-88
|
||||
c-13.2549 0 -24 10.7451 -24 24v88h-106c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM400 336v9.63184v0.000976562c0 1.37207 -0.787109 3.27246 -1.75684 4.24219l-48.3682 48.3682c-1.12598 1.125 -2.65234 1.75684 -4.24316 1.75684h-9.63184
|
||||
v-64h64z" />
|
||||
<glyph glyph-name="save" unicode="" horiz-adv-x="448"
|
||||
d="M433.941 318.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h268.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM272 368h-128v-80h128v80z
|
||||
M394 16c3.31152 0 6 2.68848 6 6v259.632c0 1.65527 -0.670898 3.15723 -1.75684 4.24316l-78.2432 78.2432v-100.118c0 -13.2549 -10.7451 -24 -24 -24h-176c-13.2549 0 -24 10.7451 -24 24v104h-42c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340z
|
||||
M224 216c48.5234 0 88 -39.4766 88 -88s-39.4766 -88 -88 -88s-88 39.4766 -88 88s39.4766 88 88 88zM224 88c22.0557 0 40 17.9443 40 40s-17.9443 40 -40 40s-40 -17.9443 -40 -40s17.9443 -40 40 -40z" />
|
||||
d="M433.941 318.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h268.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM272 368h-128v-80h128v80
|
||||
zM394 16c3.31152 0 6 2.68848 6 6v259.632v0.000976562c0 1.37207 -0.787109 3.27246 -1.75684 4.24219l-78.2432 78.2432v-100.118c0 -13.2549 -10.7451 -24 -24 -24h-176c-13.2549 0 -24 10.7451 -24 24v104h-42c-3.31152 0 -6 -2.68848 -6 -6v-340
|
||||
c0 -3.31152 2.68848 -6 6 -6h340zM224 216c48.5234 0 88 -39.4766 88 -88s-39.4766 -88 -88 -88s-88 39.4766 -88 88s39.4766 88 88 88zM224 88c22.0557 0 40 17.9443 40 40s-17.9443 40 -40 40s-40 -17.9443 -40 -40s17.9443 -40 40 -40z" />
|
||||
<glyph glyph-name="square" unicode="" horiz-adv-x="448"
|
||||
d="M400 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352zM394 16c3.2998 0 6 2.7002 6 6v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340z" />
|
||||
<glyph glyph-name="envelope" unicode=""
|
||||
@@ -181,7 +181,7 @@ c-22.5439 -17.748 -60.3359 -55.1787 -103.053 -54.9473c-42.9277 -0.231445 -81.205
|
||||
<glyph glyph-name="lightbulb" unicode="" horiz-adv-x="352"
|
||||
d="M176 368c8.83984 0 16 -7.16016 16 -16s-7.16016 -16 -16 -16c-35.2803 0 -64 -28.7002 -64 -64c0 -8.83984 -7.16016 -16 -16 -16s-16 7.16016 -16 16c0 52.9404 43.0596 96 96 96zM96.0596 -11.1699l-0.0400391 43.1797h159.961l-0.0507812 -43.1797
|
||||
c-0.00976562 -3.13965 -0.939453 -6.21973 -2.67969 -8.83984l-24.5098 -36.8398c-2.95996 -4.45996 -7.95996 -7.14062 -13.3203 -7.14062h-78.8496c-5.35059 0 -10.3506 2.68066 -13.3203 7.14062l-24.5098 36.8398c-1.75 2.62012 -2.68066 5.68945 -2.68066 8.83984z
|
||||
M176 448c97.2002 0 176 -78.7998 176 -176c0 -44.3701 -16.4502 -84.8496 -43.5498 -115.79c-16.6406 -18.9795 -42.7402 -58.79 -52.4199 -92.1602v-0.0498047h-48v0.0996094c0.00488281 4.98145 0.790039 9.78809 2.21973 14.3008
|
||||
M176 448c97.2002 0 176 -78.7998 176 -176c0 -44.3701 -16.4502 -84.8496 -43.5498 -115.79c-16.6406 -18.9795 -42.7402 -58.79 -52.4199 -92.1602v-0.0498047h-48v0.0996094c0.00390625 4.04199 0.999023 10.4482 2.21973 14.3008
|
||||
c5.67969 17.9893 22.9902 64.8496 62.0996 109.46c20.4102 23.29 31.6504 53.1699 31.6504 84.1396c0 70.5801 -57.4199 128 -128 128c-68.2803 0 -128.15 -54.3604 -127.95 -128c0.0898438 -30.9902 11.0703 -60.71 31.6104 -84.1396
|
||||
c39.3496 -44.9004 56.5801 -91.8604 62.1699 -109.67c1.42969 -4.56055 2.13965 -9.30078 2.15039 -14.0703v-0.120117h-48v0.0595703c-9.68066 33.3604 -35.7803 73.1709 -52.4209 92.1602c-27.1094 30.9307 -43.5596 71.4102 -43.5596 115.78
|
||||
c0 93.0303 73.7197 176 176 176z" />
|
||||
@@ -241,13 +241,13 @@ c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0683594l22.5361 -22.7178c4.66699 -4.
|
||||
<glyph glyph-name="share-square" unicode="" horiz-adv-x="576"
|
||||
d="M561.938 289.94c18.75 -18.7402 18.75 -49.1406 0 -67.8809l-143.998 -144c-29.9727 -29.9727 -81.9404 -9.05273 -81.9404 33.9404v53.7998c-101.266 -7.83691 -99.625 -31.6406 -84.1104 -78.7598c14.2285 -43.0889 -33.4736 -79.248 -71.0195 -55.7402
|
||||
c-51.6924 32.3057 -84.8701 83.0635 -84.8701 144.76c0 39.3408 12.2197 72.7402 36.3301 99.3008c19.8398 21.8398 47.7402 38.4697 82.9102 49.4199c36.7295 11.4395 78.3096 16.1094 120.76 17.9893v57.1982c0 42.9355 51.9258 63.9541 81.9404 33.9404zM384 112l144 144
|
||||
l-144 144v-104.09c-110.86 -0.90332 -240 -10.5166 -240 -119.851c0 -52.1396 32.79 -85.6094 62.3096 -104.06c-39.8174 120.65 48.999 141.918 177.69 143.84v-103.84zM408.74 27.5068c7.4375 2.125 14.5508 5.30566 20.9736 9.30273
|
||||
l-144 144v-104.09c-110.86 -0.90332 -240 -10.5166 -240 -119.851c0 -52.1396 32.79 -85.6094 62.3096 -104.06c-39.8174 120.65 48.999 141.918 177.69 143.84v-103.84zM408.74 27.5068c6.14844 1.75684 15.5449 5.92383 20.9736 9.30273
|
||||
c7.97656 4.95215 18.2861 -0.825195 18.2861 -10.2139v-42.5957c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h132c6.62695 0 12 -5.37305 12 -12v-4.48633c0 -4.91699 -2.9873 -9.36914 -7.56934 -11.1514
|
||||
c-13.7021 -5.33105 -26.3955 -11.5371 -38.0498 -18.585c-1.82715 -1.11523 -3.98633 -1.76953 -6.28027 -1.77734h-86.1006c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340c3.31152 0 6 2.68848 6 6v25.9658c0 5.37012 3.5791 10.0596 8.74023 11.541z
|
||||
" />
|
||||
c-13.7021 -5.33105 -26.3955 -11.5371 -38.0498 -18.585c-1.59668 -0.974609 -4.41016 -1.77051 -6.28027 -1.77734h-86.1006c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340c3.31152 0 6 2.68848 6 6v25.9658c0 5.37012 3.5791 10.0596 8.74023 11.541
|
||||
z" />
|
||||
<glyph glyph-name="compass" unicode="" horiz-adv-x="496"
|
||||
d="M347.94 318.14c16.6592 7.61035 33.8096 -9.54004 26.1992 -26.1992l-65.9697 -144.341c-3.19238 -6.9834 -8.78613 -12.5771 -15.7695 -15.7695l-144.341 -65.9697c-16.6592 -7.61035 -33.8096 9.5498 -26.1992 26.1992l65.9697 144.341
|
||||
c3.19238 6.9834 8.78613 12.5771 15.7695 15.7695zM270.58 169.42c12.4697 12.4697 12.4697 32.6904 0 45.1602s-32.6904 12.4697 -45.1602 0s-12.4697 -32.6904 0 -45.1602s32.6904 -12.4697 45.1602 0zM248 440c136.97 0 248 -111.03 248 -248s-111.03 -248 -248 -248
|
||||
d="M347.94 318.14c16.6592 7.61035 33.8096 -9.54004 26.1992 -26.1992l-65.9697 -144.341c-2.73047 -5.97363 -9.7959 -13.0391 -15.7695 -15.7695l-144.341 -65.9697c-16.6592 -7.61035 -33.8096 9.5498 -26.1992 26.1992l65.9697 144.341
|
||||
c2.73047 5.97363 9.7959 13.0391 15.7695 15.7695zM270.58 169.42c12.4697 12.4697 12.4697 32.6904 0 45.1602s-32.6904 12.4697 -45.1602 0s-12.4697 -32.6904 0 -45.1602s32.6904 -12.4697 45.1602 0zM248 440c136.97 0 248 -111.03 248 -248s-111.03 -248 -248 -248
|
||||
s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
||||
<glyph glyph-name="caret-square-down" unicode="" horiz-adv-x="448"
|
||||
d="M125.1 240h197.801c10.6992 0 16.0996 -13 8.5 -20.5l-98.9004 -98.2998c-4.7002 -4.7002 -12.2002 -4.7002 -16.9004 0l-98.8994 98.2998c-7.7002 7.5 -2.2998 20.5 8.39941 20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||
@@ -287,7 +287,7 @@ l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9
|
||||
l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136
|
||||
c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" />
|
||||
<glyph glyph-name="moon" unicode=""
|
||||
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c16.0342 -0.00292969 31.5078 -1.46875 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
|
||||
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c13.0068 -0.00195312 33.9443 -1.91797 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
|
||||
c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208
|
||||
c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" />
|
||||
<glyph glyph-name="caret-square-left" unicode="" horiz-adv-x="448"
|
||||
@@ -334,12 +334,12 @@ c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -1
|
||||
c-33.2002 0 -58 30.4004 -51.4004 62.9004l19.7002 97.0996v32h32v-32h22.1006c5.7998 0 10.6992 -4.09961 11.7998 -9.7002zM160.3 57.9004c17.9004 0 32.4004 12.0996 32.4004 27c0 14.8994 -14.5 27 -32.4004 27c-17.8994 0 -32.3994 -12.1006 -32.3994 -27
|
||||
c0 -14.9004 14.5 -27 32.3994 -27zM192.3 256v-32h-32v32h32z" />
|
||||
<glyph glyph-name="file-audio" unicode="" horiz-adv-x="384"
|
||||
d="M369.941 350.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM332.118 320
|
||||
d="M369.941 350.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM332.118 320
|
||||
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM192 60.0244c0 -10.6914 -12.9258 -16.0459 -20.4854 -8.48535l-35.5146 35.9746h-28c-6.62695 0 -12 5.37305 -12 12v56c0 6.62695 5.37305 12 12 12h28
|
||||
l35.5146 36.9473c7.56055 7.56055 20.4854 2.20605 20.4854 -8.48535v-135.951zM233.201 107.154c9.05078 9.29688 9.05957 24.1328 0.000976562 33.4385c-22.1494 22.752 12.2344 56.2461 34.3945 33.4814c27.1982 -27.9404 27.2119 -72.4443 0.000976562 -100.401
|
||||
c-21.793 -22.3857 -56.9463 10.3154 -34.3965 33.4814z" />
|
||||
<glyph glyph-name="file-video" unicode="" horiz-adv-x="384"
|
||||
d="M369.941 350.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM332.118 320
|
||||
d="M369.941 350.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM332.118 320
|
||||
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM276.687 195.303c10.0049 10.0049 27.3135 2.99707 27.3135 -11.3135v-111.976c0 -14.2939 -17.2959 -21.332 -27.3135 -11.3135l-52.6865 52.6738v-37.374
|
||||
c0 -11.0459 -8.9541 -20 -20 -20h-104c-11.0459 0 -20 8.9541 -20 20v104c0 11.0459 8.9541 20 20 20h104c11.0459 0 20 -8.9541 20 -20v-37.374z" />
|
||||
<glyph glyph-name="file-code" unicode="" horiz-adv-x="384"
|
||||
@@ -376,9 +376,9 @@ c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -41.3604 6.03027 -70.7197 14.33
|
||||
c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
||||
<glyph glyph-name="copyright" unicode=""
|
||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
||||
M363.351 93.0645c-9.61328 -9.71289 -45.5293 -41.3965 -104.064 -41.3965c-82.4297 0 -140.484 61.4248 -140.484 141.567c0 79.1514 60.2754 139.4 139.763 139.4c55.5303 0 88.7373 -26.6201 97.5928 -34.7783c2.37793 -2.1875 3.86914 -5.3252 3.86914 -8.80762
|
||||
c0 -2.39746 -0.717773 -4.64258 -1.93359 -6.51465l-18.1543 -28.1133c-3.8418 -5.9502 -11.9668 -7.28223 -17.499 -2.9209c-8.5957 6.77637 -31.8145 22.5381 -61.708 22.5381c-48.3037 0 -77.916 -35.3301 -77.916 -80.082c0 -41.5889 26.8877 -83.6924 78.2764 -83.6924
|
||||
c32.6572 0 56.8428 19.0391 65.7266 27.2256c5.26953 4.85645 13.5957 4.03906 17.8193 -1.73828l19.8652 -27.1699c1.45996 -1.98145 2.32422 -4.42969 2.32422 -7.07715c0 -3.28809 -1.32422 -6.2793 -3.47656 -8.44043z" />
|
||||
M363.351 93.0645c-9.61328 -9.71289 -45.5293 -41.3965 -104.064 -41.3965c-82.4297 0 -140.484 61.4248 -140.484 141.567c0 79.1514 60.2754 139.4 139.763 139.4c55.5303 0 88.7373 -26.6201 97.5928 -34.7783c2.13379 -1.96289 3.86523 -5.9082 3.86523 -8.80762
|
||||
c0 -1.95508 -0.864258 -4.87402 -1.92969 -6.51465l-18.1543 -28.1133c-3.8418 -5.9502 -11.9668 -7.28223 -17.499 -2.9209c-8.5957 6.77637 -31.8145 22.5381 -61.708 22.5381c-48.3037 0 -77.916 -35.3301 -77.916 -80.082c0 -41.5889 26.8877 -83.6924 78.2764 -83.6924
|
||||
c32.6572 0 56.8428 19.0391 65.7266 27.2256c5.26953 4.85645 13.5957 4.03906 17.8193 -1.73828l19.8652 -27.1699c1.28613 -1.74512 2.33008 -4.91992 2.33008 -7.08789c0 -2.72363 -1.56055 -6.5 -3.48242 -8.42969z" />
|
||||
<glyph glyph-name="closed-captioning" unicode=""
|
||||
d="M464 384c26.5 0 48 -21.5 48 -48v-288c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h416zM458 48c3.2998 0 6 2.7002 6 6v276c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-276c0 -3.2998 2.7002 -6 6 -6h404z
|
||||
M246.9 133.7c1.69922 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.6006 -56.7998 -172.801 -32.0996 -172.801 67.9004c0 97.2998 121.7 119.5 172.5 70.0996c2.10059 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.89941 -3.09961 -6.19922 -4 -9.09961 -1.7002
|
||||
@@ -398,7 +398,7 @@ c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-12v-24h88v12c
|
||||
h-32v-32h32zM96 136h224v12c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-12zM224 0v32h-32v-32h32zM504 64v160h-12c-6.62695 0 -12 5.37305 -12 12v12
|
||||
h-88v-88h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-88v-24h12c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h12zM544 0v32h-32v-32h32zM544 256v32h-32v-32h32z" />
|
||||
<glyph glyph-name="sticky-note" unicode="" horiz-adv-x="448"
|
||||
d="M448 99.8936c0 -13.2451 -5.37012 -25.252 -14.0586 -33.9404l-83.8828 -83.8818c-8.68848 -8.68848 -20.6943 -14.0596 -33.9404 -14.0596h-268.118c-26.5098 0 -48 21.4902 -48 48v351.988c0 26.5098 21.4902 48 48 48h352c26.5098 0 48 -21.4902 48 -48v-268.106z
|
||||
d="M448 99.8936c0 -10.9746 -6.29883 -26.1797 -14.0586 -33.9404l-83.8828 -83.8818c-7.75977 -7.76074 -22.9658 -14.0596 -33.9404 -14.0596h-268.118c-26.5098 0 -48 21.4902 -48 48v351.988c0 26.5098 21.4902 48 48 48h352c26.5098 0 48 -21.4902 48 -48v-268.106z
|
||||
M320 19.8936l76.1182 76.1182h-76.1182v-76.1182zM400 368h-352v-351.988h224v104c0 13.2549 10.7451 24 24 24h104v223.988z" />
|
||||
<glyph glyph-name="clone" unicode=""
|
||||
d="M464 448c26.5098 0 48 -21.4902 48 -48v-320c0 -26.5098 -21.4902 -48 -48 -48h-48v-48c0 -26.5098 -21.4902 -48 -48 -48h-320c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h48v48c0 26.5098 21.4902 48 48 48h320zM362 -16c3.31152 0 6 2.68848 6 6
|
||||
@@ -412,11 +412,11 @@ d="M408.864 368.948c48.8213 20.751 103.136 -15.0723 103.136 -67.9111v-114.443c0
|
||||
c-17.6729 0 -32 14.3271 -32 32c0 27.3301 1.1416 29.2012 -3.11035 32.9033l-97.71 85.0811c-24.8994 21.6797 -39.1797 52.8926 -39.1797 85.6338v56.9531c0 47.4277 44.8457 82.0215 91.0459 71.1807c1.96094 55.751 63.5107 87.8262 110.671 60.8057
|
||||
c29.1895 31.0713 78.8604 31.4473 108.334 -0.0214844c32.7051 18.6846 76.4121 10.3096 98.8135 -23.5879zM464 186.594v114.445c0 34.29 -52 33.8232 -52 0.676758c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v26.751
|
||||
c0 34.457 -52 33.707 -52 0.676758v-27.4287c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v40.4658c0 34.3525 -52 33.8115 -52 0.677734v-41.1436c0 -8.83594 -7.16406 -16 -16 -16h-7c-8.83594 0 -16 7.16406 -16 16v26.751
|
||||
c0 34.4023 -52 33.7744 -52 0.676758v-116.571c0 -8.83105 -7.17773 -15.9961 -16.0078 -15.9961c-4.0166 0 -7.68848 1.48242 -10.499 3.92969l-7 6.09473c-3.37012 2.93457 -5.49316 7.25293 -5.49316 12.0674v41.2275c0 34.2148 -52 33.8857 -52 0.677734v-56.9531
|
||||
c0 -18.8555 8.27441 -36.874 22.7002 -49.4365l97.71 -85.0801c12.4502 -10.8398 19.5898 -26.4463 19.5898 -42.8164v-10.2861h220v7.07617c0 13.21 2.65332 26.0791 7.88281 38.25l42.835 99.6553c3.37891 7.82715 5.28223 16.501 5.28223 25.5625v0.0498047z" />
|
||||
c0 34.4023 -52 33.7744 -52 0.676758v-116.571c0 -8.83203 -7.16797 -16 -16 -16c-3.30664 0 -8.01367 1.7627 -10.5068 3.93359l-7 6.09473c-3.03223 2.64062 -5.49316 8.04688 -5.49316 12.0674v0v41.2275c0 34.2148 -52 33.8857 -52 0.677734v-56.9531
|
||||
c0 -18.8555 8.27441 -36.874 22.7002 -49.4365l97.71 -85.0801c12.4502 -10.8398 19.5898 -26.4463 19.5898 -42.8164v-10.2861h220v7.07617c0 13.21 2.65332 26.0791 7.88281 38.25l42.835 99.6553c2.91602 6.75391 5.28223 18.207 5.28223 25.5635v0.0488281z" />
|
||||
<glyph glyph-name="hand-paper" unicode="" horiz-adv-x="448"
|
||||
d="M372.57 335.359c39.9062 5.63281 75.4297 -25.7393 75.4297 -66.3594v-131.564c-0.00292969 -15.7393 -1.80566 -30.9482 -5.19531 -45.666l-30.1836 -130.958c-3.34668 -14.5234 -16.2783 -24.8125 -31.1816 -24.8125h-222.897
|
||||
c-10.7539 0 -20.2588 5.28613 -26.0615 13.4316l-119.97 168.415c-21.2441 29.8203 -14.8047 71.3574 14.5498 93.1533c18.7754 13.9395 42.1309 16.2979 62.083 8.87109v126.13c0 44.0547 41.125 75.5439 82.4053 64.9834c23.8926 48.1963 92.3535 50.2471 117.982 0.74707
|
||||
d="M372.57 335.359c39.9062 5.63281 75.4297 -25.7393 75.4297 -66.3594v-131.564c-0.00195312 -12.7666 -2.33008 -33.2246 -5.19531 -45.666l-30.1836 -130.958c-3.34668 -14.5234 -16.2783 -24.8125 -31.1816 -24.8125h-222.897
|
||||
c-9.10352 0 -20.7793 6.01758 -26.0615 13.4316l-119.97 168.415c-21.2441 29.8203 -14.8047 71.3574 14.5498 93.1533c18.7754 13.9395 42.1309 16.2979 62.083 8.87109v126.13c0 44.0547 41.125 75.5439 82.4053 64.9834c23.8926 48.1963 92.3535 50.2471 117.982 0.74707
|
||||
c42.5186 11.1445 83.0391 -21.9346 83.0391 -65.5469v-10.8242zM399.997 137.437l-0.00195312 131.563c0 24.9492 -36.5703 25.5508 -36.5703 -0.691406v-76.3086c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v154.184
|
||||
c0 25.501 -36.5703 26.3633 -36.5703 0.691406v-154.875c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v188.309c0 25.501 -36.5703 26.3545 -36.5703 0.691406v-189c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16
|
||||
v153.309c0 25.501 -36.5713 26.3359 -36.5713 0.691406v-206.494c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832l-27.1279 38.0791c-14.3711 20.1709 -43.833 -2.33496 -29.3945 -22.6045l115.196 -161.697h201.92l27.3252 118.551
|
||||
@@ -424,46 +424,45 @@ c2.63086 11.417 3.96484 23.1553 3.96484 34.8857z" />
|
||||
<glyph glyph-name="hand-scissors" unicode=""
|
||||
d="M256 -32c-44.9561 0 -77.3428 43.2627 -64.0244 85.8535c-21.6484 13.71 -34.0156 38.7617 -30.3408 65.0068h-87.6348c-40.8037 0 -74 32.8105 -74 73.1406c0 40.3291 33.1963 73.1396 74 73.1396l94 -9.14062l-78.8496 18.6787
|
||||
c-38.3076 14.7422 -57.04 57.4707 -41.9424 95.1123c15.0303 37.4736 57.7549 55.7803 95.6416 41.2012l144.929 -55.7568c24.9551 30.5566 57.8086 43.9932 92.2178 24.7324l97.999 -54.8525c20.9746 -11.7393 34.0049 -33.8457 34.0049 -57.6904v-205.702
|
||||
c0 -30.7422 -21.4404 -57.5576 -51.7979 -64.5537l-118.999 -27.4268c-4.97168 -1.14648 -10.0889 -1.72949 -15.2031 -1.72949zM256 16.0127l70 -0.000976562c1.52441 0 2.99707 0.174805 4.42285 0.501953l119.001 27.4277
|
||||
c8.58203 1.97754 14.5762 9.29102 14.5762 17.7812v205.701c0 6.4873 -3.62109 12.542 -9.44922 15.8047l-98 54.8545c-8.13965 4.55566 -18.668 2.61914 -24.4873 -4.50781l-21.7646 -26.6475c-2.93457 -3.59375 -7.40332 -5.87305 -12.4004 -5.87305
|
||||
c-2.02246 0 -3.95703 0.375977 -5.73828 1.06152l-166.549 64.0908c-32.6543 12.5664 -50.7744 -34.5771 -19.2227 -46.7168l155.357 -59.7852c6 -2.30859 10.2539 -8.12402 10.2539 -14.9326v-11.6328c0 -8.83691 -7.16309 -16 -16 -16h-182
|
||||
c0 -30.7422 -21.4404 -57.5576 -51.7979 -64.5537l-118.999 -27.4268c-4.97168 -1.14648 -10.0889 -1.72949 -15.2031 -1.72949zM256 16.0127l70 -0.000976562c1.23633 0 3.21777 0.225586 4.42285 0.501953l119.001 27.4277
|
||||
c8.58203 1.97754 14.5762 9.29102 14.5762 17.7812v205.701c0 6.4873 -3.62109 12.542 -9.44922 15.8047l-98 54.8545c-8.13965 4.55566 -18.668 2.61914 -24.4873 -4.50781l-21.7646 -26.6475c-2.65039 -3.24512 -8.20215 -5.87891 -12.3926 -5.87891
|
||||
c-1.64062 0 -4.21484 0.477539 -5.74609 1.06738l-166.549 64.0908c-32.6543 12.5664 -50.7744 -34.5771 -19.2227 -46.7168l155.357 -59.7852c5.66016 -2.17773 10.2539 -8.86816 10.2539 -14.9326v0v-11.6328c0 -8.83691 -7.16309 -16 -16 -16h-182
|
||||
c-34.375 0 -34.4297 -50.2803 0 -50.2803h182c8.83691 0 16 -7.16309 16 -16v-6.85645c0 -8.83691 -7.16309 -16 -16 -16h-28c-25.1221 0 -25.1592 -36.5674 0 -36.5674h28c8.83691 0 16 -7.16211 16 -16v-6.85547c0 -8.83691 -7.16309 -16 -16 -16
|
||||
c-25.1201 0 -25.1602 -36.5674 0 -36.5674z" />
|
||||
<glyph glyph-name="hand-lizard" unicode="" horiz-adv-x="576"
|
||||
d="M556.686 157.458c12.6357 -19.4863 19.3145 -42.0615 19.3145 -65.2871v-124.171h-224v71.582l-99.751 38.7871c-2.7832 1.08203 -5.70996 1.63086 -8.69727 1.63086h-131.552c-30.8789 0 -56 25.1211 -56 56c0 48.5234 39.4766 88 88 88h113.709l18.333 48h-196.042
|
||||
c-44.1123 0 -80 35.8877 -80 80v8c0 30.8779 25.1211 56 56 56h293.917c24.5 0 47.084 -12.2725 60.4111 -32.8291zM528 16v76.1709c0 0.0166016 -0.0439453 0.106445 -0.0439453 0.12207c0 14.3945 -4.24219 27.8057 -11.5439 39.0498l-146.358 225.715
|
||||
c-4.44336 6.85254 -11.9707 10.9424 -20.1367 10.9424h-293.917c-4.41113 0 -8 -3.58887 -8 -8v-8c0 -17.6445 14.3555 -32 32 -32h213.471c25.2021 0 42.626 -25.293 33.6299 -48.8457l-24.5518 -64.2812c-7.05371 -18.4658 -25.0732 -30.873 -44.8398 -30.873h-113.709
|
||||
c-22.0557 0 -40 -17.9443 -40 -40c0 -4.41113 3.58887 -8 8 -8h131.552c0.0175781 0 0.0712891 -0.0273438 0.0888672 -0.0273438c9.16992 0 17.9404 -1.72461 26.0039 -4.86621l99.752 -38.7881c18.5898 -7.22852 30.6035 -24.7881 30.6035 -44.7363v-23.582h128z" />
|
||||
c-44.1123 0 -80 35.8877 -80 80v8c0 30.8779 25.1211 56 56 56h293.917c24.5 0 47.084 -12.2725 60.4111 -32.8291zM528 16v76.1709v0.0478516c0 11.7461 -5.19141 29.2734 -11.5879 39.124l-146.358 225.715c-4.44336 6.85254 -11.9707 10.9424 -20.1367 10.9424h-293.917
|
||||
c-4.41113 0 -8 -3.58887 -8 -8v-8c0 -17.6445 14.3555 -32 32 -32h213.471c25.2021 0 42.626 -25.293 33.6299 -48.8457l-24.5518 -64.2812c-7.05371 -18.4658 -25.0732 -30.873 -44.8398 -30.873h-113.709c-22.0557 0 -40 -17.9443 -40 -40c0 -4.41113 3.58887 -8 8 -8
|
||||
h131.552h0.0517578c7.44141 0 19.1074 -2.19238 26.041 -4.89355l99.752 -38.7881c18.5898 -7.22852 30.6035 -24.7881 30.6035 -44.7363v-23.582h128z" />
|
||||
<glyph glyph-name="hand-spock" unicode=""
|
||||
d="M501.03 331.824c6.92773 -11.1826 10.9697 -24.4053 10.9697 -38.5146c0 -5.92676 -0.706055 -11.6885 -2.03809 -17.208l-57.623 -241.963c-13.2236 -56.1904 -63.707 -98.1387 -123.908 -98.1387h-0.352539h-107.455
|
||||
c-0.0761719 0 -0.193359 0.00195312 -0.270508 0.00195312c-40.9248 0 -78.1475 15.9814 -105.761 42.0391l-91.3652 85.9766c-14.3076 13.4434 -23.2246 32.5547 -23.2246 53.7168c0 19.5254 7.61035 37.2861 20.0254 50.4766
|
||||
c5.31836 5.66406 29.875 29.3926 68.1152 21.8477l-24.3594 82.1973c-1.97363 6.64844 -2.97656 13.6836 -2.97656 20.9688c0 38.6953 29.8926 70.4639 67.8262 73.4531c-0.246094 2.45117 -0.34082 4.85547 -0.34082 7.37207c0 34.4199 23.585 63.376 55.4619 71.5752
|
||||
c43.248 10.9785 80.5645 -17.7012 89.6602 -53.0723l13.6836 -53.207l4.64648 22.6602c6.99023 33.5186 36.6826 58.8037 72.2373 58.916c8.73438 0 56.625 -3.26953 70.7383 -54.0801c15.0664 0.710938 46.9199 -3.50977 66.3105 -35.0176zM463.271 287.219
|
||||
c7.86914 32.9844 -42.1211 45.2695 -50.0859 11.9219l-24.8008 -104.146c-4.38867 -18.4141 -31.7783 -11.8926 -28.0557 6.2168l28.5479 139.166c7.39844 36.0703 -43.3076 45.0703 -50.1182 11.9629l-31.791 -154.971
|
||||
c-3.54883 -17.3086 -28.2832 -18.0469 -32.7109 -0.804688l-47.3262 184.035c-8.43359 32.8105 -58.3691 20.2676 -49.8652 -12.8359l42.4414 -165.039c4.81641 -18.7207 -23.3711 -26.9121 -28.9648 -8.00781l-31.3438 105.779
|
||||
c-9.6875 32.6465 -59.1191 18.2578 -49.3867 -14.625l36.0137 -121.539c6.59375 -22.2441 10.1777 -45.7803 10.1777 -70.1523c0 -6.54297 -8.05664 -10.9355 -13.4824 -5.82617l-51.123 48.1074c-24.7852 23.4082 -60.0527 -14.1875 -35.2793 -37.4902l91.3691 -85.9805
|
||||
c19.0469 -17.9736 44.75 -28.998 72.9795 -28.998h0.157227h107.455c0.0732422 0 0.138672 0.0429688 0.212891 0.0429688c37.5791 0 69.1016 26.1416 77.3564 61.2168z" />
|
||||
d="M501.03 331.824c6.05762 -9.77832 10.9746 -27.0498 10.9746 -38.5518c0 -4.80664 -0.915039 -12.499 -2.04297 -17.1709l-57.623 -241.963c-12.748 -54.1729 -68.2627 -98.1387 -123.915 -98.1387h-0.345703h-107.455h-0.224609
|
||||
c-33.8135 0 -81.2148 18.834 -105.807 42.041l-91.3652 85.9766c-12.8213 12.0469 -23.2266 36.1016 -23.2266 53.6943c0 16.1299 8.97266 38.7529 20.0273 50.499c5.31836 5.66406 29.875 29.3926 68.1152 21.8477l-24.3594 82.1973
|
||||
c-1.68164 5.66406 -3.0459 15.0576 -3.0459 20.9668c0 37.5938 30.417 70.502 67.8955 73.4551c-0.204102 2.03125 -0.369141 5.33691 -0.369141 7.37891c0 31.627 24.8594 63.6895 55.4902 71.5684c43.248 10.9785 80.5645 -17.7012 89.6602 -53.0723l13.6836 -53.207
|
||||
l4.64648 22.6602c6.76074 32.417 39.123 58.8115 72.2373 58.916c8.73438 0 56.625 -3.26953 70.7383 -54.0801c15.0664 0.710938 46.9199 -3.50977 66.3105 -35.0176zM463.271 287.219c7.86914 32.9844 -42.1211 45.2695 -50.0859 11.9219l-24.8008 -104.146
|
||||
c-4.38867 -18.4141 -31.7783 -11.8926 -28.0557 6.2168l28.5479 139.166c7.39844 36.0703 -43.3076 45.0703 -50.1182 11.9629l-31.791 -154.971c-3.54883 -17.3086 -28.2832 -18.0469 -32.7109 -0.804688l-47.3262 184.035
|
||||
c-8.43359 32.8105 -58.3691 20.2676 -49.8652 -12.8359l42.4414 -165.039c4.81641 -18.7207 -23.3711 -26.9121 -28.9648 -8.00781l-31.3438 105.779c-9.6875 32.6465 -59.1191 18.2578 -49.3867 -14.625l36.0137 -121.539
|
||||
c5.61816 -18.9521 10.1777 -50.377 10.1777 -70.1436v-0.00878906c0 -6.54297 -8.05664 -10.9355 -13.4824 -5.82617l-51.123 48.1074c-24.7852 23.4082 -60.0527 -14.1875 -35.2793 -37.4902l91.3691 -85.9805c16.9629 -16.0068 49.6592 -28.998 72.9824 -28.998h0.154297
|
||||
h107.455h0.216797c34.7402 0 69.3936 27.4443 77.3525 61.2598z" />
|
||||
<glyph glyph-name="hand-pointer" unicode="" horiz-adv-x="448"
|
||||
d="M358.182 268.639c43.1934 16.6348 89.8184 -15.7949 89.8184 -62.6387v-84c-0.000976562 -5.24023 -0.600586 -10.3037 -1.72754 -15.2041l-27.4297 -118.999c-6.98242 -30.2969 -33.7549 -51.7969 -64.5566 -51.7969h-178.286
|
||||
c-21.2588 0 -41.3682 10.4102 -53.791 27.8457l-109.699 154.001c-21.2432 29.8193 -14.8047 71.3574 14.5498 93.1523c18.8115 13.9658 42.1748 16.2822 62.083 8.87207v161.129c0 36.9443 29.7363 67 66.2861 67s66.2861 -30.0557 66.2861 -67v-73.6338
|
||||
c20.4131 2.85742 41.4678 -3.94238 56.5947 -19.6289c27.1934 12.8467 60.3799 5.66992 79.8721 -19.0986zM80.9854 168.303c-14.4004 20.2119 -43.8008 -2.38281 -29.3945 -22.6055l109.712 -154c3.43457 -4.81934 8.92871 -7.69727 14.6973 -7.69727h178.285
|
||||
c8.49219 0 15.8037 5.99414 17.7822 14.5762l27.4297 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285v84c0 25.1602 -36.5713 25.1211 -36.5713 0c0 -8.83594 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16406 -16 16v21
|
||||
c0 25.1602 -36.5713 25.1201 -36.5713 0v-21c0 -8.83594 -7.16309 -16 -16 -16h-6.85938c-8.83691 0 -16 7.16406 -16 16v35c0 25.1602 -36.5703 25.1201 -36.5703 0v-35c0 -8.83594 -7.16309 -16 -16 -16h-6.85742c-8.83691 0 -16 7.16406 -16 16v175
|
||||
c0 25.1602 -36.5713 25.1201 -36.5713 0v-241.493c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832zM176.143 48v96c0 8.83691 6.26855 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM251.571 48v96
|
||||
c0 8.83691 6.26758 16 14 16h6c7.73145 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26855 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM327 48v96c0 8.83691 6.26758 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6
|
||||
c-7.73242 0 -14 7.16309 -14 16z" />
|
||||
d="M358.182 268.639c43.1934 16.6348 89.8184 -15.7949 89.8184 -62.6387v-84c-0.000976562 -4.25 -0.775391 -11.0615 -1.72754 -15.2041l-27.4297 -118.999c-6.98242 -30.2969 -33.7549 -51.7969 -64.5566 -51.7969h-178.286c-21.2588 0 -41.3682 10.4102 -53.791 27.8457
|
||||
l-109.699 154.001c-21.2432 29.8193 -14.8047 71.3574 14.5498 93.1523c18.8115 13.9658 42.1748 16.2822 62.083 8.87207v161.129c0 36.9443 29.7363 67 66.2861 67s66.2861 -30.0557 66.2861 -67v-73.6338c20.4131 2.85742 41.4678 -3.94238 56.5947 -19.6289
|
||||
c27.1934 12.8467 60.3799 5.66992 79.8721 -19.0986zM80.9854 168.303c-14.4004 20.2119 -43.8008 -2.38281 -29.3945 -22.6055l109.712 -154c3.43457 -4.81934 8.92871 -7.69727 14.6973 -7.69727h178.285c8.49219 0 15.8037 5.99414 17.7822 14.5762l27.4297 119.001
|
||||
c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285v84c0 25.1602 -36.5713 25.1211 -36.5713 0c0 -8.83594 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16406 -16 16v21c0 25.1602 -36.5713 25.1201 -36.5713 0v-21c0 -8.83594 -7.16309 -16 -16 -16h-6.85938
|
||||
c-8.83691 0 -16 7.16406 -16 16v35c0 25.1602 -36.5703 25.1201 -36.5703 0v-35c0 -8.83594 -7.16309 -16 -16 -16h-6.85742c-8.83691 0 -16 7.16406 -16 16v175c0 25.1602 -36.5713 25.1201 -36.5713 0v-241.493c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832z
|
||||
M176.143 48v96c0 8.83691 6.26855 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM251.571 48v96c0 8.83691 6.26758 16 14 16h6c7.73145 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26855 -16 -14 -16h-6
|
||||
c-7.73242 0 -14 7.16309 -14 16zM327 48v96c0 8.83691 6.26758 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16z" />
|
||||
<glyph glyph-name="hand-peace" unicode="" horiz-adv-x="448"
|
||||
d="M362.146 256.024c42.5908 13.3184 85.8535 -19.0684 85.8535 -64.0244l-0.0117188 -70.001c-0.000976562 -5.24023 -0.600586 -10.3027 -1.72949 -15.2031l-27.4268 -118.999c-6.99707 -30.3564 -33.8105 -51.7969 -64.5547 -51.7969h-205.702
|
||||
d="M362.146 256.024c42.5908 13.3184 85.8535 -19.0684 85.8535 -64.0244l-0.0117188 -70.001c-0.000976562 -4.25 -0.775391 -11.0615 -1.72949 -15.2031l-27.4268 -118.999c-6.99707 -30.3564 -33.8105 -51.7969 -64.5547 -51.7969h-205.702
|
||||
c-23.8447 0 -45.9502 13.0303 -57.6904 34.0059l-54.8525 97.999c-19.2607 34.4092 -5.82422 67.2617 24.7324 92.2178l-55.7568 144.928c-14.5791 37.8867 3.72754 80.6113 41.2012 95.6416c37.6406 15.0977 80.3691 -3.63477 95.1123 -41.9424l18.6787 -78.8496
|
||||
l-9.14062 94c0 40.8037 32.8096 74 73.1396 74s73.1406 -33.1963 73.1406 -74v-87.6348c26.2451 3.6748 51.2959 -8.69238 65.0068 -30.3408zM399.987 122l-0.000976562 70c0 25.1602 -36.5674 25.1201 -36.5674 0c0 -8.83691 -7.16309 -16 -16 -16h-6.85547
|
||||
c-8.83789 0 -16 7.16309 -16 16v28c0 25.1592 -36.5674 25.1221 -36.5674 0v-28c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v182c0 34.4297 -50.2803 34.375 -50.2803 0v-182c0 -8.83691 -7.16309 -16 -16 -16h-11.6328
|
||||
c-6.80859 0 -12.624 4.25391 -14.9326 10.2539l-59.7842 155.357c-12.1396 31.5518 -59.2842 13.4326 -46.7168 -19.2227l64.0898 -166.549c0.685547 -1.78125 1.07812 -3.71875 1.07812 -5.74121c0 -4.99707 -2.2959 -9.46289 -5.88965 -12.3975l-26.6475 -21.7646
|
||||
c-8.83789 0 -16 7.16309 -16 16v28c0 25.1592 -36.5674 25.1221 -36.5674 0v-28c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v182c0 34.4297 -50.2803 34.375 -50.2803 0v-182c0 -8.83691 -7.16309 -16 -16 -16h-11.6328v0
|
||||
c-6.06445 0 -12.7549 4.59375 -14.9326 10.2539l-59.7842 155.357c-12.1396 31.5518 -59.2842 13.4326 -46.7168 -19.2227l64.0898 -166.549c0.589844 -1.53125 1.06738 -4.10547 1.06738 -5.74609c0 -4.19043 -2.63379 -9.74219 -5.87891 -12.3926l-26.6475 -21.7646
|
||||
c-7.12695 -5.81934 -9.06445 -16.3467 -4.50781 -24.4873l54.8535 -98c3.26367 -5.82812 9.31934 -9.44922 15.8057 -9.44922h205.701c8.49121 0 15.8037 5.99414 17.7812 14.5762l27.4277 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285z" />
|
||||
<glyph glyph-name="registered" unicode=""
|
||||
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
||||
M366.442 73.791c4.40332 -7.99219 -1.37012 -17.791 -10.5107 -17.791h-42.8096c-0.00488281 0 -0.000976562 -0.0126953 -0.00585938 -0.0126953c-4.58594 0 -8.57422 2.58301 -10.5869 6.37305l-47.5156 89.3027h-31.958v-83.6631c0 -6.61719 -5.38281 -12 -12 -12
|
||||
h-38.5674c-6.61719 0 -12 5.38281 -12 12v248.304c0 6.61719 5.38281 12 12 12h78.667c71.251 0 101.498 -32.749 101.498 -85.252c0 -31.6123 -15.2148 -59.2969 -39.4824 -73.1758c3.02148 -4.61719 0.225586 0.199219 53.2715 -96.085zM256.933 208.094
|
||||
c20.9131 0 32.4307 11.5186 32.4316 32.4316c0 19.5752 -6.5127 31.709 -38.9297 31.709h-27.377v-64.1406h33.875z" />
|
||||
M366.442 73.791c4.40332 -7.99219 -1.37012 -17.791 -10.5107 -17.791h-42.8096h-0.0126953c-3.97559 0 -8.71582 2.84961 -10.5801 6.36035l-47.5156 89.3027h-31.958v-83.6631c0 -6.61719 -5.38281 -12 -12 -12h-38.5674c-6.61719 0 -12 5.38281 -12 12v248.304
|
||||
c0 6.61719 5.38281 12 12 12h78.667c71.251 0 101.498 -32.749 101.498 -85.252c0 -31.6123 -15.2148 -59.2969 -39.4824 -73.1758c3.02148 -4.61719 0.225586 0.199219 53.2715 -96.085zM256.933 208.094c20.9131 0 32.4307 11.5186 32.4316 32.4316
|
||||
c0 19.5752 -6.5127 31.709 -38.9297 31.709h-27.377v-64.1406h33.875z" />
|
||||
<glyph glyph-name="calendar-plus" unicode="" horiz-adv-x="448"
|
||||
d="M336 156v-24c0 -6.59961 -5.40039 -12 -12 -12h-76v-76c0 -6.59961 -5.40039 -12 -12 -12h-24c-6.59961 0 -12 5.40039 -12 12v76h-76c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h76v76c0 6.59961 5.40039 12 12 12h24c6.59961 0 12 -5.40039 12 -12
|
||||
v-76h76c6.59961 0 12 -5.40039 12 -12zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40
|
||||
@@ -482,9 +481,9 @@ c6.62695 0 12 -5.37305 12 -12v-52h48zM394 -16c3.31152 0 6 2.68848 6 6v298h-352v-
|
||||
c-4.66699 4.70508 -4.6377 12.3027 0.0673828 16.9707l22.7197 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l44.1035 -44.4609l111.072 110.182c4.70508 4.66699 12.3027 4.63672 16.9707 -0.0683594l22.5361 -22.7178
|
||||
c4.66699 -4.70508 4.63672 -12.3027 -0.0683594 -16.9697z" />
|
||||
<glyph glyph-name="map" unicode="" horiz-adv-x="576"
|
||||
d="M560.02 416c8.4502 0 15.9805 -6.83008 15.9805 -16.0195v-346.32c0 -13.4707 -8.32422 -24.9951 -20.1201 -29.71l-151.83 -52.8105c-6.23242 -2.02832 -12.9023 -3.12305 -19.8076 -3.12305c-7.07324 0 -13.8799 1.15039 -20.2422 3.27344l-172 60.71l-170.05 -62.8398
|
||||
c-1.99023 -0.790039 -4 -1.16016 -5.95996 -1.16016c-8.45996 0 -15.9902 6.83008 -15.9902 16.0195v346.32c0.00292969 13.4697 8.32617 24.9932 20.1201 29.71l151.83 52.8105c6.43945 2.08984 13.1201 3.13965 19.8096 3.13965
|
||||
c7.06641 -0.00292969 13.8789 -1.16602 20.2402 -3.28027l172 -60.7197h0.00976562l170.05 62.8398c1.98047 0.790039 4 1.16016 5.95996 1.16016zM224 357.58v-285.97l128 -45.1904v285.97zM48 29.9502l127.36 47.0801l0.639648 0.229492v286.2l-128 -44.5303v-288.979z
|
||||
d="M560.02 416c8.4502 0 15.9805 -6.83008 15.9805 -16.0195v-346.32c0 -11.9609 -9.01367 -25.2705 -20.1201 -29.71l-151.83 -52.8105c-5.32617 -1.7334 -14.1953 -3.13965 -19.7969 -3.13965c-5.7373 0 -14.8105 1.47363 -20.2529 3.29004l-172 60.71l-170.05 -62.8398
|
||||
c-1.99023 -0.790039 -4 -1.16016 -5.95996 -1.16016c-8.45996 0 -15.9902 6.83008 -15.9902 16.0195v346.32c0.00292969 11.959 9.0166 25.2686 20.1201 29.71l151.83 52.8105c6.43945 2.08984 13.1201 3.13965 19.8096 3.13965
|
||||
c5.73242 -0.00195312 14.8008 -1.47168 20.2402 -3.28027l172 -60.7197h0.00976562l170.05 62.8398c1.98047 0.790039 4 1.16016 5.95996 1.16016zM224 357.58v-285.97l128 -45.1904v285.97zM48 29.9502l127.36 47.0801l0.639648 0.229492v286.2l-128 -44.5303v-288.979z
|
||||
M528 65.0801v288.97l-127.36 -47.0693l-0.639648 -0.240234v-286.19z" />
|
||||
<glyph glyph-name="comment-alt" unicode=""
|
||||
d="M448 448c35.2998 0 64 -28.7002 64 -64v-288c0 -35.2998 -28.7002 -64 -64 -64h-144l-124.9 -93.5996c-2.19922 -1.7002 -4.69922 -2.40039 -7.09961 -2.40039c-6.2002 0 -12 4.90039 -12 12v84h-96c-35.2998 0 -64 28.7002 -64 64v288c0 35.2998 28.7002 64 64 64h384z
|
||||
@@ -498,16 +497,16 @@ c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h160c8.7998 0 16 -7.200
|
||||
<glyph glyph-name="handshake" unicode="" horiz-adv-x="640"
|
||||
d="M519.2 320.1h120.8v-255.699h-64c-17.5 0 -31.7998 14.1992 -31.9004 31.6992h-57.8994c-1.7998 -8.19922 -5.2998 -16.0996 -10.9004 -23l-26.2002 -32.2998c-15.7998 -19.3994 -41.8994 -25.5 -64 -16.7998c-13.5 -16.5996 -30.5996 -24 -48.7998 -24
|
||||
c-15.0996 0 -28.5996 5.09961 -41.0996 15.9004c-31.7998 -21.9004 -74.7002 -21.3008 -105.601 3.7998l-84.5996 76.3994h-9.09961c-0.100586 -17.5 -14.3008 -31.6992 -31.9004 -31.6992h-64v255.699h118l47.5996 47.6006c10.5 10.3994 24.8008 16.2998 39.6006 16.2998
|
||||
h226.8c15.4326 0 29.4326 -6.22168 39.5996 -16.2998zM48 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16zM438 103.3c2.7002 3.40039 2.2002 8.5 -1.2002 11.2998l-108.2 87.8008l-8.19922 -7.5
|
||||
h226.8v0c12.7812 0 30.5225 -7.30273 39.5996 -16.2998zM48 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16zM438 103.3c2.7002 3.40039 2.2002 8.5 -1.2002 11.2998l-108.2 87.8008l-8.19922 -7.5
|
||||
c-40.3008 -36.8008 -86.7002 -11.8008 -101.5 4.39941c-26.7002 29 -25 74.4004 4.39941 101.3l38.7002 35.5h-56.7002c-2 -0.799805 -3.7002 -1.5 -5.7002 -2.2998l-61.6992 -61.5996h-41.9004v-128.101h27.7002l97.2998 -88
|
||||
c16.0996 -13.0996 41.4004 -10.5 55.2998 6.60059l15.6006 19.2002l36.7998 -31.5c3 -2.40039 12 -4.90039 18 2.39941l30 36.5l23.8994 -19.3994c3.5 -2.80078 8.5 -2.2002 11.3008 1.19922zM544 144.1v128h-44.7002l-61.7002 61.6006
|
||||
c-1.39941 1.5 -3.39941 2.2998 -5.5 2.2998l-83.6992 -0.200195c-10 0 -19.6006 -3.7002 -27 -10.5l-65.6006 -60.0996c-9.7002 -8.7998 -10.5 -24 -1.2002 -33.9004c8.90039 -9.39941 25.1006 -8.7002 34.6006 0l55.2002 50.6006c6.5 5.89941 16.5996 5.5 22.5996 -1
|
||||
l10.9004 -11.7002c6 -6.5 5.5 -16.6006 -1 -22.6006l-12.5 -11.3994l102.699 -83.4004c2.80078 -2.2998 5.40039 -4.89941 7.7002 -7.7002h69.2002zM592 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16z
|
||||
" />
|
||||
<glyph glyph-name="envelope-open" unicode=""
|
||||
d="M494.586 283.484c10.6523 -8.80762 17.4141 -22.1064 17.4141 -36.9932v-262.491c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v262.515c0 14.9355 6.80469 28.2705 17.5146 37.0771c4.08008 3.35449 110.688 89.0996 135.15 108.549
|
||||
c22.6992 18.1426 60.1299 55.8594 103.335 55.8594c43.4365 0 81.2314 -38.1914 103.335 -55.8594c23.5283 -18.707 130.554 -104.773 135.251 -108.656zM464 -10v253.632c0 0.00195312 0.00390625 0.000976562 0.00390625 0.00292969
|
||||
c0 1.88184 -0.869141 3.56152 -2.22754 4.66016c-15.8633 12.8232 -108.793 87.5752 -132.366 106.316c-17.5527 14.0195 -49.7168 45.3887 -73.4102 45.3887c-23.6016 0 -55.2451 -30.8799 -73.4102 -45.3887c-23.5713 -18.7393 -116.494 -93.4795 -132.364 -106.293
|
||||
d="M494.586 283.484c9.6123 -7.94824 17.4141 -24.5205 17.4141 -36.9932v-262.491c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v262.515c0 12.5166 7.84668 29.1279 17.5146 37.0771c4.08008 3.35449 110.688 89.0996 135.15 108.549
|
||||
c22.6992 18.1426 60.1299 55.8594 103.335 55.8594c43.4365 0 81.2314 -38.1914 103.335 -55.8594c23.5283 -18.707 130.554 -104.773 135.251 -108.656zM464 -10v253.632v0.00488281c0 1.5791 -0.996094 3.66602 -2.22363 4.6582
|
||||
c-15.8633 12.8232 -108.793 87.5752 -132.366 106.316c-17.5527 14.0195 -49.7168 45.3887 -73.4102 45.3887c-23.6016 0 -55.2451 -30.8799 -73.4102 -45.3887c-23.5713 -18.7393 -116.494 -93.4795 -132.364 -106.293
|
||||
c-1.40918 -1.13965 -2.22559 -2.85254 -2.22559 -4.66504v-253.653c0 -3.31152 2.68848 -6 6 -6h404c3.31152 0 6 2.68848 6 6zM432.009 177.704c4.24902 -5.15918 3.46484 -12.7949 -1.74512 -16.9814c-28.9746 -23.2822 -59.2734 -47.5967 -70.9287 -56.8623
|
||||
c-22.6992 -18.1436 -60.1299 -55.8604 -103.335 -55.8604c-43.4521 0 -81.2871 38.2373 -103.335 55.8604c-11.2793 8.9668 -41.7441 33.4131 -70.9268 56.8643c-5.20996 4.1875 -5.99316 11.8223 -1.74512 16.9814l15.2578 18.5283
|
||||
c4.17773 5.07227 11.6572 5.84277 16.7793 1.72559c28.6182 -23.001 58.5654 -47.0352 70.5596 -56.5713c17.5527 -14.0195 49.7168 -45.3887 73.4102 -45.3887c23.6016 0 55.2461 30.8799 73.4102 45.3887c11.9941 9.53516 41.9434 33.5703 70.5625 56.5684
|
||||
@@ -556,11 +555,10 @@ c6.09961 -6.2002 6.09961 -16.4004 0 -22.6006l-58.2998 -59.2998v-84.5l71.8994 42.
|
||||
c7.5 4.39941 17.2002 1.7998 21.5 -5.90039l7.90039 -13.9004c4.2998 -7.69922 1.7002 -17.5 -5.7998 -21.8994l-39.2002 -23l34.0996 -9.2998c8.40039 -2.30078 13.3008 -11.1006 11.1006 -19.6006l-4.10059 -15.5c-2.2998 -8.5 -10.8994 -13.5996 -19.2998 -11.2998
|
||||
l-79.7002 21.7002l-71.8994 -42.2002l71.7998 -42.2002l79.7002 21.7002c8.39941 2.2998 17.0996 -2.7998 19.2998 -11.2998l4.09961 -15.5c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.6006l-34.0996 -9.2998z" />
|
||||
<glyph glyph-name="trash-alt" unicode="" horiz-adv-x="448"
|
||||
d="M268 32c-6.62305 0 -12 5.37695 -12 12v216c0 6.62305 5.37695 12 12 12h24c6.62305 0 12 -5.37695 12 -12v-216c0 -6.62305 -5.37695 -12 -12 -12h-24zM432 368c8.83105 0 16 -7.16895 16 -16v-16c0 -8.83105 -7.16895 -16 -16 -16h-16v-336
|
||||
c0 -26.4922 -21.5078 -48 -48 -48h-288c-26.4922 0 -48 21.5078 -48 48v336h-16c-8.83105 0 -16 7.16895 -16 16v16c0 8.83105 7.16895 16 16 16h82.4102l34.0195 56.7002c8.39258 13.9844 23.6777 23.2998 41.1602 23.2998h100.82
|
||||
c0.0078125 0 -0.015625 0.0517578 -0.0078125 0.0517578c17.4824 0 32.7949 -9.36719 41.1875 -23.3516l34 -56.7002h82.4102zM171.84 397.09l-17.4502 -29.0898h139.221l-17.46 29.0898c-1.0498 1.74707 -2.95898 2.91016 -5.14355 2.91016h-0.00683594h-94
|
||||
c-0.00585938 0 -0.00683594 0.00683594 -0.0126953 0.00683594c-2.18457 0 -4.09766 -1.16992 -5.14746 -2.91699zM368 -16v336h-288v-336h288zM156 32c-6.62305 0 -12 5.37695 -12 12v216c0 6.62305 5.37695 12 12 12h24c6.62305 0 12 -5.37695 12 -12v-216
|
||||
c0 -6.62305 -5.37695 -12 -12 -12h-24z" />
|
||||
d="M268 32c-6.62402 0 -12 5.37598 -12 12v216c0 6.62402 5.37598 12 12 12h24c6.62402 0 12 -5.37598 12 -12v-216c0 -6.62402 -5.37598 -12 -12 -12h-24zM432 368c8.83203 0 16 -7.16797 16 -16v-16c0 -8.83203 -7.16797 -16 -16 -16h-16v-336
|
||||
c0 -26.4961 -21.5039 -48 -48 -48h-288c-26.4961 0 -48 21.5039 -48 48v336h-16c-8.83203 0 -16 7.16797 -16 16v16c0 8.83203 7.16797 16 16 16h82.4102l34.0195 56.7002c7.71875 12.8613 26.1572 23.2998 41.1572 23.2998h0.00292969h100.82h0.0224609
|
||||
c15 0 33.4385 -10.4385 41.1572 -23.2998l34 -56.7002h82.4102zM171.84 397.09l-17.4502 -29.0898h139.221l-17.46 29.0898c-0.96582 1.60645 -3.26953 2.91016 -5.14355 2.91016h-0.00683594h-94h-0.0166016c-1.87402 0 -4.17871 -1.30371 -5.14355 -2.91016zM368 -16v336
|
||||
h-288v-336h288zM156 32c-6.62402 0 -12 5.37598 -12 12v216c0 6.62402 5.37598 12 12 12h24c6.62402 0 12 -5.37598 12 -12v-216c0 -6.62402 -5.37598 -12 -12 -12h-24z" />
|
||||
<glyph glyph-name="images" unicode="" horiz-adv-x="576"
|
||||
d="M480 32v-16c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256c0 26.5098 21.4902 48 48 48h16v-48h-10c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v10h48zM522 368h-372
|
||||
c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v244c0 3.31152 -2.68848 6 -6 6zM528 416c26.5098 0 48 -21.4902 48 -48v-256c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256
|
||||
@@ -586,9 +584,9 @@ d="M464 448c4.09961 0 7.7998 -2 10.0996 -5.40039l99.9004 -147.199c2.90039 -4.400
|
||||
c2.2002 3.40039 6 5.40039 10 5.40039h352zM444.7 400h-56.7998l51.6992 -96h68.4004zM242.6 400l-51.5996 -96h194l-51.7002 96h-90.7002zM131.3 400l-63.2998 -96h68.4004l51.6992 96h-56.7998zM88.2998 256l119.7 -160l-68.2998 160h-51.4004zM191.2 256l96.7998 -243.3
|
||||
l96.7998 243.3h-193.6zM368 96l119.6 160h-51.3994z" />
|
||||
<glyph glyph-name="money-bill-alt" unicode="" horiz-adv-x="640"
|
||||
d="M320 304c53.0195 0 96 -50.1396 96 -112c0 -61.8701 -43 -112 -96 -112c-53.0195 0 -96 50.1504 -96 112c0 61.8604 42.9805 112 96 112zM360 136v16c0 4.41992 -3.58008 8 -8 8h-16v88c0 4.41992 -3.58008 8 -8 8h-13.5801
|
||||
c-4.91113 0 -9.50586 -1.49316 -13.3096 -4.03027l-15.3301 -10.2197c-2.15332 -1.43262 -3.55957 -3.88379 -3.55957 -6.66113c0 -1.6377 0.493164 -3.16113 1.33887 -4.42871l8.88086 -13.3105c1.43164 -2.15234 3.88379 -3.55957 6.66113 -3.55957
|
||||
c1.6377 0 3.16016 0.494141 4.42871 1.33984l0.469727 0.310547v-55.4404h-16c-4.41992 0 -8 -3.58008 -8 -8v-16c0 -4.41992 3.58008 -8 8 -8h64c4.41992 0 8 3.58008 8 8zM608 384c17.6699 0 32 -14.3301 32 -32v-320c0 -17.6699 -14.3301 -32 -32 -32h-576
|
||||
d="M320 304c53.0195 0 96 -50.1396 96 -112c0 -61.8701 -43 -112 -96 -112c-53.0195 0 -96 50.1504 -96 112c0 61.8604 42.9805 112 96 112zM360 136v16c0 4.41992 -3.58008 8 -8 8h-16v88c0 4.41992 -3.58008 8 -8 8h-13.5801h-0.000976562
|
||||
c-4.01074 0 -9.97266 -1.80566 -13.3086 -4.03027l-15.3301 -10.2197c-1.96777 -1.30957 -3.56445 -4.29004 -3.56445 -6.65332c0 -1.33691 0.601562 -3.32422 1.34375 -4.43652l8.88086 -13.3105c1.30859 -1.9668 4.29004 -3.56445 6.65332 -3.56445
|
||||
c1.33691 0 3.32422 0.602539 4.43652 1.34473l0.469727 0.310547v-55.4404h-16c-4.41992 0 -8 -3.58008 -8 -8v-16c0 -4.41992 3.58008 -8 8 -8h64c4.41992 0 8 3.58008 8 8zM608 384c17.6699 0 32 -14.3301 32 -32v-320c0 -17.6699 -14.3301 -32 -32 -32h-576
|
||||
c-17.6699 0 -32 14.3301 -32 32v320c0 17.6699 14.3301 32 32 32h576zM592 112v160c-35.3496 0 -64 28.6504 -64 64h-416c0 -35.3496 -28.6504 -64 -64 -64v-160c35.3496 0 64 -28.6504 64 -64h416c0 35.3496 28.6504 64 64 64z" />
|
||||
<glyph glyph-name="window-close" unicode=""
|
||||
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v340c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z
|
||||
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
BIN
dist/qmi-cloud/fa-regular-400.c20b5b7362d8d7bb7edd.woff2
vendored
Normal file
BIN
dist/qmi-cloud/fa-regular-400.f89ea91ecd1ca2db7e09.woff
vendored
Normal file
BIN
dist/qmi-cloud/fa-solid-900.b15db15f746f29ffa026.woff2
vendored
Normal file
BIN
dist/qmi-cloud/fa-solid-900.bea989e82b07e9687c26.woff
vendored
Normal file
|
Before Width: | Height: | Size: 893 KiB After Width: | Height: | Size: 876 KiB |
4
dist/qmi-cloud/index.html
vendored
@@ -6,8 +6,8 @@
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="assets/favicon.ico">
|
||||
<link rel="stylesheet" href="styles.b2e9059fb6aa834811ea.css"></head>
|
||||
<link rel="stylesheet" href="styles.d596c43fc1f81eecfae1.css"></head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<script src="runtime.c51bd5b1c616d9ffddc1.js" defer></script><script src="polyfills-es5.6fef7e679f78bcc42760.js" nomodule defer></script><script src="polyfills.51f5cc3d1309de3a873d.js" defer></script><script src="scripts.1af868998801499c8755.js" defer></script><script src="main.5c4c2f7e4461741ce9f1.js" defer></script></body>
|
||||
<script src="runtime.689ba4fd6cadb82c1ac2.js" defer></script><script src="polyfills-es5.2f1b30b563fe6f309b2d.js" nomodule defer></script><script src="polyfills.60117177d3b4f4827ace.js" defer></script><script src="scripts.73c34722d75b092f2620.js" defer></script><script src="main.ece894ac50d4edc475b5.js" defer></script></body>
|
||||
</html>
|
||||
|
||||
1
dist/qmi-cloud/main.5c4c2f7e4461741ce9f1.js
vendored
1
dist/qmi-cloud/main.ece894ac50d4edc475b5.js
vendored
Normal file
1
dist/qmi-cloud/scripts.73c34722d75b092f2620.js
vendored
Normal file
80
dist/qmi-cloud/styles.b2e9059fb6aa834811ea.css
vendored
80
dist/qmi-cloud/styles.d596c43fc1f81eecfae1.css
vendored
Normal file
@@ -77,6 +77,7 @@ services:
|
||||
- ../qmi-cloud-provisions:/provisions
|
||||
- ./logs:/logs
|
||||
- ./costexport:/var/www/app/costexport
|
||||
- ./photos:/var/www/app/photos
|
||||
#- ./certs:/var/www/app/server/certs
|
||||
depends_on:
|
||||
- mongo
|
||||
@@ -95,6 +96,7 @@ services:
|
||||
container_name: qmi-cloud-worker
|
||||
restart: on-failure
|
||||
environment:
|
||||
- HOSTNAME_URL=http://localhost:3000
|
||||
- REDIS_URL=redis://redis
|
||||
- MONGO_URI=mongodb://root:example@mongo/qmicloud?authSource=admin
|
||||
- PROJECT_PATH=%PWD%
|
||||
@@ -106,7 +108,7 @@ services:
|
||||
command: "sh -c 'npm run start:dev'"
|
||||
volumes:
|
||||
# -- Dev only volumes
|
||||
- ./worker:/app/worker
|
||||
- ./qmi-cloud-worker:/app/worker
|
||||
# -------------------
|
||||
- ./logs:/logs
|
||||
- /var/run/docker.sock:/home/docker.sock
|
||||
|
||||
470
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qmi-cloud-app",
|
||||
"version": "1.1.3",
|
||||
"version": "1.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -440,6 +440,206 @@
|
||||
"integrity": "sha512-IZG1kvw48JyFRy7bfMHqBixWrEHZmXmkP5DWsi5Tw6KusaczkMghI20BevCkodPcajXWHAUHNKyp1tlE3OnH0w==",
|
||||
"dev": true
|
||||
},
|
||||
"@angular/localize": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@angular/localize/-/localize-9.0.7.tgz",
|
||||
"integrity": "sha512-nlmcxEVZmz4ty1MXE1OFnHMYndedQUunZY4MB3lm7c8MJrRnI5x7zAOvkwI+sUF0Hy3rfjkO7ddOzGBfDtjPPA==",
|
||||
"requires": {
|
||||
"@babel/core": "7.8.3",
|
||||
"glob": "7.1.2",
|
||||
"yargs": "13.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz",
|
||||
"integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.8.3",
|
||||
"@babel/generator": "^7.8.3",
|
||||
"@babel/helpers": "^7.8.3",
|
||||
"@babel/parser": "^7.8.3",
|
||||
"@babel/template": "^7.8.3",
|
||||
"@babel/traverse": "^7.8.3",
|
||||
"@babel/types": "^7.8.3",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.1",
|
||||
"json5": "^2.1.0",
|
||||
"lodash": "^4.17.13",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.4.1",
|
||||
"source-map": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.13.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz",
|
||||
"integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.13.0",
|
||||
"jsesc": "^2.5.1",
|
||||
"source-map": "^0.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/types": {
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz",
|
||||
"integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.12.11",
|
||||
"lodash": "^4.17.19",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
|
||||
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
|
||||
},
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"requires": {
|
||||
"locate-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"requires": {
|
||||
"p-locate": "^3.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"requires": {
|
||||
"p-limit": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"requires": {
|
||||
"emoji-regex": "^7.0.1",
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"requires": {
|
||||
"ansi-regex": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "13.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.1.0.tgz",
|
||||
"integrity": "sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==",
|
||||
"requires": {
|
||||
"cliui": "^4.0.0",
|
||||
"find-up": "^3.0.0",
|
||||
"get-caller-file": "^2.0.1",
|
||||
"os-locale": "^3.1.0",
|
||||
"require-directory": "^2.1.1",
|
||||
"require-main-filename": "^2.0.0",
|
||||
"set-blocking": "^2.0.0",
|
||||
"string-width": "^3.0.0",
|
||||
"which-module": "^2.0.0",
|
||||
"y18n": "^4.0.0",
|
||||
"yargs-parser": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
|
||||
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@angular/platform-browser": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.0.7.tgz",
|
||||
@@ -455,6 +655,120 @@
|
||||
"resolved": "https://registry.npmjs.org/@angular/router/-/router-9.0.7.tgz",
|
||||
"integrity": "sha512-uKru9F/Zju//gg6INl54abnlpLdEUUO/GpCfMk4zqu8LCZGNFta6OY7VT+9DK9Vdrh/XUD70oE9WoelcRwwTYA=="
|
||||
},
|
||||
"@azure/abort-controller": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.4.tgz",
|
||||
"integrity": "sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==",
|
||||
"requires": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/arm-compute": {
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/arm-compute/-/arm-compute-15.0.0.tgz",
|
||||
"integrity": "sha512-ElV2MuYZ+B2+ygMx2iiM/u3C7WDRruZjkXzfk5p2O+UbWxjG6j/686OH3T+VSDqmzg+47AnIOTLu2v0u0H8FOw==",
|
||||
"requires": {
|
||||
"@azure/ms-rest-azure-js": "^2.0.1",
|
||||
"@azure/ms-rest-js": "^2.0.4",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@azure/arm-dns": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/arm-dns/-/arm-dns-4.0.0.tgz",
|
||||
"integrity": "sha512-VhI8NRd6hyHKxMSTqUWpozQ//D4S1CuxFMRDao/Bzs0ETUIUem4DNOJAk5Zn5+IWfDDpJnRlLqLCspfMD5/V8A==",
|
||||
"requires": {
|
||||
"@azure/ms-rest-azure-js": "^2.0.1",
|
||||
"@azure/ms-rest-js": "^2.0.4",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@azure/core-auth": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.3.0.tgz",
|
||||
"integrity": "sha512-kSDSZBL6c0CYdhb+7KuutnKGf2geeT+bCJAgccB0DD7wmNJSsQPcF7TcuoZX83B7VK4tLz/u+8sOO/CnCsYp8A==",
|
||||
"requires": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/ms-rest-azure-env": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz",
|
||||
"integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw=="
|
||||
},
|
||||
"@azure/ms-rest-azure-js": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.1.0.tgz",
|
||||
"integrity": "sha512-CjZjB8apvXl5h97Ck6SbeeCmU0sk56YPozPtTyGudPp1RGoHXNjFNtoOvwOG76EdpmMpxbK10DqcygI16Lu60Q==",
|
||||
"requires": {
|
||||
"@azure/core-auth": "^1.1.4",
|
||||
"@azure/ms-rest-js": "^2.2.0",
|
||||
"tslib": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"@azure/ms-rest-js": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.3.0.tgz",
|
||||
"integrity": "sha512-8NOnHgovi61NpcUld53zRkY/IcQJBBO48VeMntNTUtaPo8yYYTnu1hWRvp6b6vpBnur7HGmuj692J9li5Kx6/Q==",
|
||||
"requires": {
|
||||
"@azure/core-auth": "^1.1.4",
|
||||
"abort-controller": "^3.0.0",
|
||||
"form-data": "^2.5.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"tough-cookie": "^3.0.1",
|
||||
"tslib": "^1.10.0",
|
||||
"tunnel": "0.0.6",
|
||||
"uuid": "^3.3.2",
|
||||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
||||
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
|
||||
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
|
||||
"requires": {
|
||||
"ip-regex": "^2.1.0",
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@azure/ms-rest-nodeauth": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.9.tgz",
|
||||
"integrity": "sha512-+GdDHUJlWtIDanRZemFooLy68NsBDhN/Oni9DSFeoXIFNGlSe1IOes8/IRkQdrNXyUvBanuzzR7I5WYYzYQsmA==",
|
||||
"requires": {
|
||||
"@azure/ms-rest-azure-env": "^2.0.0",
|
||||
"@azure/ms-rest-js": "^2.0.4",
|
||||
"adal-node": "^0.1.28"
|
||||
}
|
||||
},
|
||||
"@babel/code-frame": {
|
||||
"version": "7.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz",
|
||||
@@ -1337,6 +1651,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz",
|
||||
"integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q=="
|
||||
},
|
||||
"@ng-bootstrap/ng-bootstrap": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-6.2.0.tgz",
|
||||
"integrity": "sha512-wqwhnJFyEwvzWQJjXrEt+7oBTSvu2qPbdYvUFYhDVzOJLWB5M7YEhDAkMrfHQJ0pZNBMGr580FqYue+XiURY0Q=="
|
||||
},
|
||||
"@ngtools/webpack": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-9.0.7.tgz",
|
||||
@@ -1488,8 +1807,7 @@
|
||||
"@types/node": {
|
||||
"version": "8.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz",
|
||||
"integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ=="
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.3",
|
||||
@@ -1753,6 +2071,14 @@
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
@@ -1794,13 +2120,6 @@
|
||||
"uuid": "^3.1.0",
|
||||
"xmldom": ">= 0.1.x",
|
||||
"xpath.js": "~1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "8.10.61",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.61.tgz",
|
||||
"integrity": "sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"adm-zip": {
|
||||
@@ -2370,36 +2689,12 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
|
||||
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
|
||||
},
|
||||
"azure-arm-compute": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/azure-arm-compute/-/azure-arm-compute-10.0.0.tgz",
|
||||
"integrity": "sha512-ehafNtcMKI6c00FT+xhPWPtzhYgHCZ675TUsaJ1FJ2bSpznih5EUrpir/4w519T4zbFBigszhnRK6eBkl78I9g==",
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"requires": {
|
||||
"ms-rest": "^2.5.0",
|
||||
"ms-rest-azure": "^2.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
|
||||
"integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
|
||||
"requires": {
|
||||
"lodash": "^4.14.0"
|
||||
}
|
||||
},
|
||||
"ms-rest-azure": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/ms-rest-azure/-/ms-rest-azure-2.6.0.tgz",
|
||||
"integrity": "sha512-J6386a9krZ4VtU7CRt+Ypgo9RGf8+d3gjMBkH7zbkM4zzkhbbMOYiPRaZ+bHZcfihkKLlktTgA6rjshTjF329A==",
|
||||
"requires": {
|
||||
"adal-node": "^0.1.28",
|
||||
"async": "2.6.0",
|
||||
"moment": "^2.22.2",
|
||||
"ms-rest": "^2.3.2",
|
||||
"request": "^2.88.0",
|
||||
"uuid": "^3.2.1"
|
||||
}
|
||||
}
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
@@ -2488,6 +2783,13 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"barracuda-api": {
|
||||
"version": "git+https://gitlab.com/qlik_gear/barracuda-api-node.git#a4a15a6766f3c66196ed1854cc301575c218323f",
|
||||
"from": "git+https://gitlab.com/qlik_gear/barracuda-api-node.git#0.0.3",
|
||||
"requires": {
|
||||
"axios": "^0.21.1"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
|
||||
@@ -4938,11 +5240,6 @@
|
||||
"nan": "^2.14.0"
|
||||
}
|
||||
},
|
||||
"duplexer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
|
||||
},
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
@@ -5311,6 +5608,11 @@
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz",
|
||||
@@ -6052,6 +6354,11 @@
|
||||
"integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
|
||||
"dev": true
|
||||
},
|
||||
"gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
|
||||
},
|
||||
"geojson-vt": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz",
|
||||
@@ -9059,44 +9366,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"ms-rest": {
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/ms-rest/-/ms-rest-2.5.4.tgz",
|
||||
"integrity": "sha512-VeqCbawxRM6nhw0RKNfj7TWL7SL8PB6MypqwgylXCi+u412uvYoyY/kSmO8n06wyd8nIcnTbYToCmSKFMI1mCg==",
|
||||
"requires": {
|
||||
"duplexer": "^0.1.1",
|
||||
"is-buffer": "^1.1.6",
|
||||
"is-stream": "^1.1.0",
|
||||
"moment": "^2.21.0",
|
||||
"request": "^2.88.0",
|
||||
"through": "^2.3.8",
|
||||
"tunnel": "0.0.5",
|
||||
"uuid": "^3.2.1"
|
||||
}
|
||||
},
|
||||
"ms-rest-azure": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms-rest-azure/-/ms-rest-azure-3.0.0.tgz",
|
||||
"integrity": "sha512-cttN01/TtMDB4v3rt/WQ/slgffB6jcUYxcPzcL0VNSB+WFPE1j4y5ICNHMuD1RaNNekCYMI4Pv51BDQ/BXNq7Q==",
|
||||
"requires": {
|
||||
"adal-node": "^0.1.28",
|
||||
"async": "2.6.0",
|
||||
"moment": "^2.22.2",
|
||||
"ms-rest": "^2.3.2",
|
||||
"request": "^2.88.0",
|
||||
"uuid": "^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
|
||||
"integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
|
||||
"requires": {
|
||||
"lodash": "^4.14.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"multicast-dns": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
|
||||
@@ -9214,6 +9483,11 @@
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"node-fetch-npm": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz",
|
||||
@@ -11353,11 +11627,14 @@
|
||||
"qmi-cloud-common": {
|
||||
"version": "file:qmi-cloud-common",
|
||||
"requires": {
|
||||
"@azure/arm-compute": "^15.0.0",
|
||||
"@azure/arm-dns": "^4.0.0",
|
||||
"@azure/ms-rest-nodeauth": "^3.0.7",
|
||||
"@hapi/boom": "^9.1.0",
|
||||
"azure-arm-compute": "^10.0.0",
|
||||
"axios": "^0.21.1",
|
||||
"barracuda-api": "git+https://gitlab.com/qlik_gear/barracuda-api-node.git#0.0.3",
|
||||
"bull": "^3.11.0",
|
||||
"mongoose": "^5.7.4",
|
||||
"ms-rest-azure": "^3.0.0",
|
||||
"nodemailer": "^6.4.2"
|
||||
}
|
||||
},
|
||||
@@ -13594,7 +13871,8 @@
|
||||
"through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
||||
"dev": true
|
||||
},
|
||||
"through2": {
|
||||
"version": "2.0.5",
|
||||
@@ -13802,9 +14080,9 @@
|
||||
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.5.tgz",
|
||||
"integrity": "sha512-gj5sdqherx4VZKMcBA4vewER7zdK25Td+z1npBqpbDys4eJrLx+SlYjJvq1bDXs2irkuJM5pf8ktaEQVipkrbA=="
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
@@ -13990,9 +14268,9 @@
|
||||
}
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
|
||||
"integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg=="
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.0.tgz",
|
||||
"integrity": "sha512-sCs4H3pCytsb5K7i072FAEC9YlSYFIbosvM0tAKAlpSSUgD7yC1iXSEGdl5XrDKQ1YUB+p/HDzYrSG2H2Vl36g=="
|
||||
},
|
||||
"unicode-canonical-property-names-ecmascript": {
|
||||
"version": "1.0.4",
|
||||
@@ -15066,7 +15344,6 @@
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
|
||||
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
@@ -15075,13 +15352,12 @@
|
||||
"xmlbuilder": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
|
||||
},
|
||||
"xmldom": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.3.0.tgz",
|
||||
"integrity": "sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g=="
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz",
|
||||
"integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA=="
|
||||
},
|
||||
"xmlhttprequest-ssl": {
|
||||
"version": "1.5.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qmi-cloud-app",
|
||||
"version": "1.1.8",
|
||||
"version": "1.3.0",
|
||||
"scripts": {
|
||||
"start": "node -r esm server/server.js",
|
||||
"start:dev": "nodemon -r esm server/server.js",
|
||||
@@ -27,6 +27,7 @@
|
||||
"adal-angular4": "^4.0.12",
|
||||
"angular-bootstrap-md": "9.0.0",
|
||||
"animate.css": "^3.7.2",
|
||||
"axios": "^0.21.1",
|
||||
"body-parser": "^1.19.0",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bull-arena": "^2.6.4",
|
||||
|
||||
0
photos/.keep
Normal file
@@ -1,7 +1,7 @@
|
||||
# Stage 1: NOTE: context is actually ../
|
||||
FROM node:13.8-alpine AS sources
|
||||
FROM node:15.12.0-alpine AS sources
|
||||
|
||||
RUN apk --no-cache add yarn
|
||||
RUN apk --no-cache add yarn git
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -11,7 +11,7 @@ ADD ./qmi-cloud-common ../qmi-cloud-common
|
||||
RUN yarn install --production
|
||||
|
||||
# Stage 2:
|
||||
FROM node:13.8-alpine AS production
|
||||
FROM node:15.12.0-alpine AS production
|
||||
WORKDIR /app
|
||||
COPY --from=sources /app ./
|
||||
|
||||
|
||||
@@ -1,22 +1,36 @@
|
||||
# Examples
|
||||
|
||||
## Check Destroy
|
||||
```
|
||||
docker run --net=host \
|
||||
-e MONGO_URI="mongodb://root:example@localhost:27017/qmicloud?authSource=admin" \
|
||||
-e API_KEY="c229219ccdd72d11e8ea253fd3876d247e5f489c9c84922cabdfb0cc194d8ff398a8d8d6528d8241efc99add2207e0ec75122a1b2c5598cc340cbe6b7c3c0dbf" \
|
||||
qlikgear/qmi-cloud-cli:latest -s checkdestroy -t warning -p 4 -r test
|
||||
qlikgear/qmi-cloud-cli:latest -s checkdestroy -t warning -r test
|
||||
```
|
||||
|
||||
## Init DB
|
||||
```
|
||||
docker run --net=host \
|
||||
-e MONGO_URI="mongodb://root:example@localhost:27017/qmicloud?authSource=admin" \
|
||||
qlikgear/qmi-cloud-cli:latest -s initdb
|
||||
```
|
||||
|
||||
## Check Destroy
|
||||
```
|
||||
docker run --net=host -e MONGO_URI=$MONGO_URI -e API_KEY=$API_KEY qlikgear/qmi-cloud-cli:latest -s checkdestroy -t warning -p 20 -r test
|
||||
docker run --net=host -e MONGO_URI=$MONGO_URI -e API_KEY=$API_KEY qlikgear/qmi-cloud-cli:latest -s checkdestroy -t warning -r test
|
||||
```
|
||||
|
||||
## Check Stop
|
||||
```
|
||||
docker run --net=host -e MONGO_URI=$MONGO_URI -e API_KEY=$API_KEY qlikgear/qmi-cloud-cli:latest -s checkstop -t warning -p 4 -r test
|
||||
docker run --net=host -e SMTP_EMAIL_SENDER=http://172.20.16.4:9200/sendemail -e MONGO_URI=$MONGO_URI -e API_KEY=$API_KEY qlikgear/qmi-cloud-cli:latest -s checkstop -t warning -r test
|
||||
```
|
||||
|
||||
## Check Errors
|
||||
```
|
||||
docker run --net=host -e MONGO_URI=$MONGO_URI qlikgear/qmi-cloud-cli:latest -s checkerror -r test
|
||||
```
|
||||
|
||||
## Move Destroyed
|
||||
```
|
||||
docker run --net=host -e MONGO_URI=$MONGO_URI -v $PWD/qmi-cloud-provisions:/provisions qlikgear/qmi-cloud-cli:latest -s movedestroyed -r "2020-31-12T00:00:00.000Z"
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
var myArgs = process.argv.slice(2);
|
||||
|
||||
if ( myArgs.length < 3 ) {
|
||||
if ( myArgs.length < 2 ) {
|
||||
console.log("Missing args", myArgs);
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -12,9 +12,7 @@ const moment = require('moment');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
|
||||
const IS_REAL = myArgs[2] !== 'test';
|
||||
const STOPPED_PERIOD = myArgs[1]; //20 Days
|
||||
const STOPPED_PERIOD_IS_EXTERNAL = Math.ceil(myArgs[1]/2); //10 Days
|
||||
const IS_REAL = myArgs[1] !== 'test';
|
||||
const WARNING_DAYS = 2;
|
||||
|
||||
//---
|
||||
@@ -63,7 +61,8 @@ async function init(type) {
|
||||
var filter = {
|
||||
"isDestroyed":false,
|
||||
"isDeleted": false,
|
||||
"statusVms": "Stopped"
|
||||
"statusVms": "Stopped",
|
||||
"vmImage": {"$exists": true}
|
||||
};
|
||||
if ( type === "warning" ) {
|
||||
filter.pendingNextAction = {$ne: "destroy"};
|
||||
@@ -84,11 +83,15 @@ async function init(type) {
|
||||
typeSchedule = 'OnSchedule';
|
||||
}
|
||||
timeRunning(p);
|
||||
|
||||
let stoppedPeriod = p._scenarioDoc.allowedInnactiveDays || 20;
|
||||
let stoppedPeriodExternal = Math.ceil(stoppedPeriod/2);
|
||||
|
||||
var limit;
|
||||
if ( type === "warning" ) {
|
||||
limit = p.isExternalAccess? 24*(STOPPED_PERIOD_IS_EXTERNAL-WARNING_DAYS) : 24*(STOPPED_PERIOD-WARNING_DAYS);
|
||||
limit = p.isExternalAccess? 24*(stoppedPeriodExternal-WARNING_DAYS) : 24*(stoppedPeriod-WARNING_DAYS);
|
||||
} else if ( type === "exec" ) {
|
||||
limit = p.isExternalAccess? (24*STOPPED_PERIOD_IS_EXTERNAL) : (24*STOPPED_PERIOD);
|
||||
limit = p.isExternalAccess? (24*stoppedPeriodExternal) : (24*stoppedPeriod);
|
||||
}
|
||||
if ( !IS_REAL ) {
|
||||
console.log(`${p._id} (${typeSchedule}) - limit: ${limit} hs - actual duration: ${p.duration.hours} hs`);
|
||||
@@ -106,9 +109,11 @@ const doSendEmailDestroyWarning = async function(p, limit, typeSchedule) {
|
||||
let msg = `Send warning DESTROY email - ${p.user.displayName} (${p.user.upn}) about provision '${p._scenarioDoc.title}' (${p._id} - ${typeSchedule}) being 'Inactive' more than ${limit} hours, (exactly ${p.duration.complete})`;
|
||||
console.log(msg);
|
||||
if ( IS_REAL ) {
|
||||
db.event.add({ user: p.user._id, provision: p._id, type: 'vms.warning-destroy' });
|
||||
await db.provision.update(p._id, {"pendingNextAction": "destroy"});
|
||||
await sendEmail.sendWillDestroyIn24(p, p._scenarioDoc, Math.floor(limit/24), WARNING_DAYS);
|
||||
await db.notification.add({ provision: p._id.toString(), type: 'warningDestroy', message: msg });
|
||||
await sendEmail.sendWillDestroyIn24(p, p._scenarioDoc, Math.floor(limit/24), WARNING_DAYS);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -118,6 +123,7 @@ const doDestroy = async function(p, limit, typeSchedule) {
|
||||
let msg = `Provision destroyed - ${p.user.displayName} (${p.user.upn}) about provision '${p._scenarioDoc.title}' (${p._id} - ${typeSchedule}) being 'Inactive' more than ${limit} hours (exactly ${p.duration.complete})`
|
||||
console.log(msg);
|
||||
if ( IS_REAL ) {
|
||||
db.event.add({ user: p.user._id, provision: p._id, type: 'vms.exec-destroy' });
|
||||
await postDestroy(p);
|
||||
await db.notification.add({ provision: p._id.toString(), type: 'destroy', message: msg });
|
||||
}
|
||||
|
||||
59
qmi-cloud-cli/jobs/error5.js
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
var myArgs = process.argv.slice(2);
|
||||
|
||||
if ( myArgs.length < 1 ) {
|
||||
console.log("Missing args", myArgs);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const IS_REAL = myArgs[0] !== 'test';
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const sendEmail = require("qmi-cloud-common/send-email");
|
||||
|
||||
async function asyncForEach(array, callback) {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
}
|
||||
}
|
||||
|
||||
const doSendEmailErrorProvision = async function(p) {
|
||||
let msg = `Send prrovision ERROR email - ${p.user.displayName} (${p.user.upn}) about provision '${p._scenarioDoc.title}' (${p._id}) provisioned with 'Errors'`;
|
||||
console.log(msg);
|
||||
if ( IS_REAL ) {
|
||||
db.event.add({ user: p.user._id, provision: p._id, type: 'vms.warning-error' });
|
||||
await db.notification.add({ provision: p._id.toString(), type: 'warningError', message: msg });
|
||||
await sendEmail.sendProvisionError(p, p._scenarioDoc);
|
||||
}
|
||||
};
|
||||
|
||||
async function init() {
|
||||
let provisions = await db.provision.get({
|
||||
"isDestroyed":false,
|
||||
"isDeleted": false,
|
||||
"status": "error"
|
||||
});
|
||||
|
||||
await asyncForEach(provisions.results, async function(p) {
|
||||
await doSendEmailErrorProvision(p);
|
||||
});
|
||||
}
|
||||
|
||||
function check() {
|
||||
init().then(function(){
|
||||
db.mongoose.connection.close()
|
||||
process.exit(0);
|
||||
|
||||
}).catch(function(e){
|
||||
db.mongoose.connection.close()
|
||||
console.log("Error", e);
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------
|
||||
check();
|
||||
61
qmi-cloud-cli/jobs/move_destroyed.js
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
var myArgs = process.argv.slice(2);
|
||||
|
||||
if ( myArgs.length < 1 ) {
|
||||
console.log("Missing args", myArgs);
|
||||
process.exit(0);
|
||||
}
|
||||
console.log("myArgs", myArgs);
|
||||
const ISODATE = new Date(myArgs[0]).toISOString();
|
||||
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
async function asyncForEach(array, callback) {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
}
|
||||
}
|
||||
|
||||
async function init() {
|
||||
let provisions = await db.provision.get({
|
||||
"isDestroyed":true,
|
||||
"isDeleted": false,
|
||||
"created": { "$lt" : ISODATE }
|
||||
});
|
||||
await asyncForEach(provisions.results, async function(p) {
|
||||
await doMoveDestroyed(p);
|
||||
});
|
||||
}
|
||||
|
||||
const doMoveDestroyed = async function(provision) {
|
||||
var scenarioFolder = `${provision.scenario}_${provision._id}`;
|
||||
console.log(`Moving scenario: /provisions/${scenarioFolder}`);
|
||||
if (fs.existsSync(`/provisions/${scenarioFolder}`)) {
|
||||
fs.moveSync(`/provisions/${scenarioFolder}`, `/provisions/deleted/${scenarioFolder}`, { overwrite: true })
|
||||
console.log(`OK.`);
|
||||
} else {
|
||||
console.log(`NOK: It does not exist.`);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function check() {
|
||||
init().then(function(){
|
||||
db.mongoose.connection.close()
|
||||
process.exit(0);
|
||||
|
||||
}).catch(function(e){
|
||||
db.mongoose.connection.close()
|
||||
console.log("Error", e);
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------
|
||||
check();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
|
||||
var myArgs = process.argv.slice(2);
|
||||
|
||||
if ( myArgs.length < 3 ) {
|
||||
if ( myArgs.length < 2 ) {
|
||||
console.log("Missing args", myArgs);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const IS_REAL = myArgs[2] !== 'test';
|
||||
|
||||
const RUNNING_PERIOD = myArgs[1]; // 7 Days
|
||||
const RUNNING_PERIOD_ON_SCHEDULE = Math.ceil(myArgs[1]/2); // ~ 4 Days
|
||||
const IS_REAL = myArgs[1] !== 'test';
|
||||
const WARNING_DAYS = 1;
|
||||
|
||||
// ---
|
||||
@@ -17,7 +14,7 @@ const WARNING_DAYS = 1;
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const sendEmail = require("qmi-cloud-common/send-email");
|
||||
const moment = require('moment');
|
||||
const azurecli = require('qmi-cloud-common/azurecli');
|
||||
const cli = require('qmi-cloud-common/cli');
|
||||
|
||||
function timeRunningIs24x7(p) {
|
||||
let runningFromTime = p.runningFrom? new Date(p.runningFrom).getTime() : new Date(p.created).getTime();
|
||||
@@ -41,6 +38,18 @@ function timeRunningOnSchedule(p) {
|
||||
};
|
||||
}
|
||||
|
||||
function timeRunningOnSchedule2(p) {
|
||||
|
||||
let startTimestamp = p.startDateOnSchedule? new Date(p.startDateOnSchedule).getTime() : 0;
|
||||
let endTimestamp = p.endDateOnSchedule? new Date(p.endDateOnSchedule).getTime() : 0;
|
||||
let totalTimeOnschedule = Math.abs(endTimestamp - startTimestamp);
|
||||
let duration = moment.duration(totalTimeOnschedule);
|
||||
p.duration = {
|
||||
hours: Math.floor(duration.asHours()),
|
||||
complete: Math.floor(duration.asDays()) +"d "+duration.hours()+"h "+duration.minutes()
|
||||
};
|
||||
}
|
||||
|
||||
async function asyncForEach(array, callback) {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
@@ -52,7 +61,8 @@ async function init(type) {
|
||||
var filter = {
|
||||
"isDestroyed": false,
|
||||
"isDeleted": false,
|
||||
"statusVms": "Running"
|
||||
"statusVms": "Running",
|
||||
"vmImage": { "$exists": true }
|
||||
};
|
||||
if ( type === "warning" ) {
|
||||
filter.pendingNextAction = { $ne: "stopVms" };
|
||||
@@ -69,18 +79,19 @@ async function init(type) {
|
||||
|
||||
await asyncForEach(provisions.results, async function(p) {
|
||||
//Only if 24x7
|
||||
var typeSchedule = "24x7";
|
||||
var periodDays = RUNNING_PERIOD;
|
||||
let typeSchedule = "24x7";
|
||||
let periodDays = p._scenarioDoc.allowed24x7RunningDays;
|
||||
if ( !p.schedule || p.schedule.is24x7 ) {
|
||||
// 24x7
|
||||
timeRunningIs24x7(p);
|
||||
periodDays = RUNNING_PERIOD;
|
||||
periodDays = p._scenarioDoc.allowed24x7RunningDays;
|
||||
} else if ( p.schedule && !p.schedule.is24x7 ) {
|
||||
timeRunningOnSchedule(p);
|
||||
// OnSchedule
|
||||
timeRunningOnSchedule2(p);
|
||||
typeSchedule = 'OnSchedule';
|
||||
let onScheduleRenewed = p.schedule.onScheduleRenewed? p.schedule.onScheduleRenewed : 1;
|
||||
periodDays = RUNNING_PERIOD_ON_SCHEDULE * onScheduleRenewed;
|
||||
periodDays = p._scenarioDoc.allowedOnScheduleRunningDays;
|
||||
}
|
||||
var limit;
|
||||
let limit;
|
||||
if ( type === "warning" ) {
|
||||
limit = 24*(periodDays-WARNING_DAYS);
|
||||
} else if ( type === "exec" ) {
|
||||
@@ -102,9 +113,10 @@ const doSendEmailWarning = async function(p, limit, typeSchedule) {
|
||||
let msg = `Send warning STOP email - ${p.user.displayName} (${p.user.upn}) about provision '${p._scenarioDoc.title}' (${p._id} - ${typeSchedule}) being 'Running' more than ${limit} hours, (exactly ${p.duration.complete})`;
|
||||
console.log(msg);
|
||||
if ( IS_REAL ) {
|
||||
db.event.add({ user: p.user._id, provision: p._id, type: 'vms.warning-stop' });
|
||||
await db.provision.update(p._id, {"pendingNextAction": "stopVms"});
|
||||
await sendEmail.sendWillStopIn24(p, p._scenarioDoc, Math.floor(limit/24), WARNING_DAYS);
|
||||
await db.notification.add({ provision: p._id.toString(), type: 'warningStop', message: msg });
|
||||
await sendEmail.sendWillStopIn24(p, p._scenarioDoc, Math.floor(limit/24), WARNING_DAYS);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -118,14 +130,15 @@ const doStop = async function(p, limit, typeSchedule) {
|
||||
if (p.schedule){
|
||||
//Disable Divvy
|
||||
await db.schedule.update(p.schedule._id, {"isStartupTimeEnable": false});
|
||||
await azurecli.updateVmsTags(p._id, {
|
||||
await cli.updateVmsTags(p._id, {
|
||||
"24x7": false,
|
||||
"StartupTime": false,
|
||||
"ShutdownTime": false
|
||||
});
|
||||
}
|
||||
//Stop VMs indefinitely
|
||||
await azurecli.deallocate(p._id, true);
|
||||
db.event.add({ user: p.user._id, provision: p._id, type: 'vms.exec-stop' });
|
||||
await cli.deallocate(p._id, true);
|
||||
await db.notification.add({ provision: p._id.toString(), type: 'stop', message: msg });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"name": "qmi-cloud-cli",
|
||||
"version": "1.1.5",
|
||||
"version": "1.3.0",
|
||||
"scripts": {
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"qmi-cloud-common": "../qmi-cloud-common",
|
||||
"node-fetch": "^2.6.0",
|
||||
"moment": "^2.24.0"
|
||||
"moment": "^2.24.0",
|
||||
"axios": "^0.21.1",
|
||||
"fs-extra": "^8.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,33 @@ helpFunction()
|
||||
{
|
||||
echo ""
|
||||
echo "Usage: $0 -s script"
|
||||
echo -e "\t-s Type of script ( checkstop | checkdestroy | initdb )"
|
||||
echo -e "\t-s Type of script ( checkstop | checkdestroy | checkerror | movedestroyed | initdb )"
|
||||
exit 1 # Exit script after printing help
|
||||
}
|
||||
|
||||
helpFunctionCheck()
|
||||
{
|
||||
echo ""
|
||||
echo "Usage: $0 -s script -t type -p period -r realortest"
|
||||
echo -e "\t-s Type of script ( checkstop | checkdestroy | initdb )"
|
||||
echo "Usage: $0 -s script [-t type -r realortest]"
|
||||
echo -e "\t-s Type of script ( checkstop | checkdestroy | checkerror )"
|
||||
echo -e "\t-t Type of script ( warning | exec )"
|
||||
echo -e "\t-p Period (number of days)"
|
||||
echo -e "\t-r Type of script (test | real)"
|
||||
echo -e "\t-r Indicate whether is for test or real execution ( test | real )"
|
||||
exit 1 # Exit script after printing help
|
||||
}
|
||||
|
||||
helpFunctionCheck2()
|
||||
{
|
||||
echo ""
|
||||
echo "Usage: $0 -s checkerror [-r realortest]"
|
||||
echo -e "\t-r Indicate whether is for test or real execution ( test | real )"
|
||||
exit 1 # Exit script after printing help
|
||||
}
|
||||
|
||||
helpFunctionCheck3()
|
||||
{
|
||||
echo ""
|
||||
echo "Usage: $0 -s movedestroyed [-r isodate]"
|
||||
echo -e "\t-r An ISODATE (ie: '2020-31-12T00:00:00.000Z') to movedestroyed backwards"
|
||||
exit 1 # Exit script after printing help
|
||||
}
|
||||
|
||||
@@ -25,7 +40,6 @@ do
|
||||
case "$opt" in
|
||||
s ) script="$OPTARG" ;;
|
||||
t ) type="$OPTARG" ;;
|
||||
p ) period="$OPTARG" ;;
|
||||
r ) realortest="$OPTARG" ;;
|
||||
? ) helpFunction ;; # Print helpFunction in case parameter is non-existent
|
||||
esac
|
||||
@@ -33,25 +47,25 @@ done
|
||||
|
||||
if [ -z "$script" ]
|
||||
then
|
||||
echo "Some or all of the parameters are empty";
|
||||
echo "Script not recognised";
|
||||
helpFunction
|
||||
fi
|
||||
|
||||
if [ "$script" = "checkstop" ] || [ "$script" = "checkdestroy" ]
|
||||
then
|
||||
if [ -z "$type" ] || [ -z "$period" ] || [ -z "$realortest" ]
|
||||
if [ -z "$type" ] || [ -z "$realortest" ]
|
||||
then
|
||||
echo "Some or all of the parameters are empty";
|
||||
helpFunctionCheck
|
||||
else
|
||||
if [ "$script" = "checkstop" ]
|
||||
then
|
||||
$BASEDIR/checkstop.sh $type $period $realortest
|
||||
$BASEDIR/checkstop.sh $type $realortest
|
||||
fi
|
||||
|
||||
if [ "$script" = "checkdestroy" ]
|
||||
then
|
||||
$BASEDIR/checkdestroy.sh $type $period $realortest
|
||||
$BASEDIR/checkdestroy.sh $type $realortest
|
||||
fi
|
||||
fi
|
||||
elif [ "$script" = "initdb" ]
|
||||
@@ -64,5 +78,24 @@ then
|
||||
echo "\$MONGO_URI=$MONGO_URI"
|
||||
node $BASEDIR/../jobs/db-init.js
|
||||
fi
|
||||
elif [ "$script" = "checkerror" ]
|
||||
then
|
||||
if [ -z "$realortest" ]
|
||||
then
|
||||
echo "Some or all of the parameters are empty";
|
||||
helpFunctionCheck2
|
||||
else
|
||||
node $BASEDIR/../jobs/error5.js $realortest
|
||||
fi
|
||||
elif [ "$script" = "movedestroyed" ]
|
||||
then
|
||||
if [ -z "$realortest" ]
|
||||
then
|
||||
echo "Some or all of the parameters are empty";
|
||||
helpFunctionCheck3
|
||||
else
|
||||
node $BASEDIR/../jobs/move_destroyed.js $realortest
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ d=`date`
|
||||
echo "------ $d"
|
||||
echo "------ SCRIPT: $0"
|
||||
echo "------ TYPE: $1"
|
||||
echo "------ PERIOD: $2"
|
||||
echo "------ TEST/REAL: $3"
|
||||
echo "------ TEST/REAL: $2"
|
||||
|
||||
if [ -z "$MONGO_URI" ]
|
||||
then
|
||||
@@ -22,4 +21,4 @@ else
|
||||
echo "\$API_KEY=$API_KEY"
|
||||
fi
|
||||
|
||||
node $BASEDIR/../jobs/destroy5.js $1 $2 $3
|
||||
node $BASEDIR/../jobs/destroy5.js $1 $2
|
||||
|
||||
14
qmi-cloud-cli/shell-utils/checkerror.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
BASEDIR=$(dirname "$0")
|
||||
d=`date`
|
||||
echo "------ $d"
|
||||
echo "------ SCRIPT: $0"
|
||||
|
||||
if [ -z "$MONGO_URI" ]
|
||||
then
|
||||
echo "\$MONGO_URI is empty"
|
||||
exit
|
||||
else
|
||||
echo "\$MONGO_URI=$MONGO_URI"
|
||||
fi
|
||||
|
||||
node $BASEDIR/../jobs/error5.js $1
|
||||
@@ -3,8 +3,7 @@ d=`date`
|
||||
echo "------ $d"
|
||||
echo "------ SCRIPT: $0"
|
||||
echo "------ TYPE: $1"
|
||||
echo "------ PERIOD: $2"
|
||||
echo "------ TEST/REAL: $3"
|
||||
echo "------ TEST/REAL: $2"
|
||||
|
||||
if [ -z "$MONGO_URI" ]
|
||||
then
|
||||
@@ -22,4 +21,4 @@ else
|
||||
echo "\$API_KEY=$API_KEY"
|
||||
fi
|
||||
|
||||
node $BASEDIR/../jobs/stop5.js $1 $2 $3
|
||||
node $BASEDIR/../jobs/stop5.js $1 $2
|
||||
@@ -2,6 +2,70 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@azure/abort-controller@^1.0.0":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.4.tgz#fd3c4d46c8ed67aace42498c8e2270960250eafd"
|
||||
integrity sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@azure/arm-compute@^15.0.0":
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/arm-compute/-/arm-compute-15.0.0.tgz#5d0d0c1db16adbb6db3d33ca376b120c68e6ae23"
|
||||
integrity sha512-ElV2MuYZ+B2+ygMx2iiM/u3C7WDRruZjkXzfk5p2O+UbWxjG6j/686OH3T+VSDqmzg+47AnIOTLu2v0u0H8FOw==
|
||||
dependencies:
|
||||
"@azure/ms-rest-azure-js" "^2.0.1"
|
||||
"@azure/ms-rest-js" "^2.0.4"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@azure/core-auth@^1.1.4":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.2.0.tgz#a5a181164e99f8446a3ccf9039345ddc9bb63bb9"
|
||||
integrity sha512-KUl+Nwn/Sm6Lw5d3U90m1jZfNSL087SPcqHLxwn2T6PupNKmcgsEbDjHB25gDvHO4h7pBsTlrdJAY7dz+Qk8GA==
|
||||
dependencies:
|
||||
"@azure/abort-controller" "^1.0.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@azure/ms-rest-azure-env@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz#45809f89763a480924e21d3c620cd40866771625"
|
||||
integrity sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==
|
||||
|
||||
"@azure/ms-rest-azure-js@^2.0.1":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.1.0.tgz#8c90b31468aeca3146b06c7144b386fd4827f64c"
|
||||
integrity sha512-CjZjB8apvXl5h97Ck6SbeeCmU0sk56YPozPtTyGudPp1RGoHXNjFNtoOvwOG76EdpmMpxbK10DqcygI16Lu60Q==
|
||||
dependencies:
|
||||
"@azure/core-auth" "^1.1.4"
|
||||
"@azure/ms-rest-js" "^2.2.0"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@azure/ms-rest-js@^2.0.4", "@azure/ms-rest-js@^2.2.0":
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-2.2.3.tgz#8f0085f7768c69f17b3cdb20ce95728b452dc304"
|
||||
integrity sha512-sXOhOu/37Tr8428f32Jwuwga975Xw64pYg1UeUwOBMhkNgtn5vUuNRa3fhmem+I6f8EKoi6hOsYDFlaHeZ52jA==
|
||||
dependencies:
|
||||
"@azure/core-auth" "^1.1.4"
|
||||
"@types/node-fetch" "^2.3.7"
|
||||
"@types/tunnel" "0.0.1"
|
||||
abort-controller "^3.0.0"
|
||||
form-data "^2.5.0"
|
||||
node-fetch "^2.6.0"
|
||||
tough-cookie "^3.0.1"
|
||||
tslib "^1.10.0"
|
||||
tunnel "0.0.6"
|
||||
uuid "^3.3.2"
|
||||
xml2js "^0.4.19"
|
||||
|
||||
"@azure/ms-rest-nodeauth@^3.0.7":
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.7.tgz#73c399b0aef45c75104324b6617aa4e0a6c27875"
|
||||
integrity sha512-7Q1MyMB+eqUQy8JO+virSIzAjqR2UbKXE/YQZe+53gC8yakm8WOQ5OzGfPP+eyHqeRs6bQESyw2IC5feLWlT2A==
|
||||
dependencies:
|
||||
"@azure/ms-rest-azure-env" "^2.0.0"
|
||||
"@azure/ms-rest-js" "^2.0.4"
|
||||
adal-node "^0.1.28"
|
||||
|
||||
"@hapi/boom@^9.1.0":
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.0.tgz#0d9517657a56ff1e0b42d0aca9da1b37706fec56"
|
||||
@@ -14,11 +78,38 @@
|
||||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.0.4.tgz#e80ad4e8e8d2adc6c77d985f698447e8628b6010"
|
||||
integrity sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw==
|
||||
|
||||
"@types/node-fetch@^2.3.7":
|
||||
version "2.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb"
|
||||
integrity sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
form-data "^3.0.0"
|
||||
|
||||
"@types/node@*":
|
||||
version "14.14.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
|
||||
integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==
|
||||
|
||||
"@types/node@^8.0.47":
|
||||
version "8.10.61"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.61.tgz#d299136ce54bcaf1abaa4a487f9e4bedf6b0d393"
|
||||
integrity sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q==
|
||||
|
||||
"@types/tunnel@0.0.1":
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.1.tgz#0d72774768b73df26f25df9184273a42da72b19c"
|
||||
integrity sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
adal-node@^0.1.28:
|
||||
version "0.1.28"
|
||||
resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.1.28.tgz#468c4bb3ebbd96b1270669f4b9cba4e0065ea485"
|
||||
@@ -56,13 +147,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
async@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
|
||||
integrity sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==
|
||||
dependencies:
|
||||
lodash "^4.14.0"
|
||||
|
||||
async@>=0.6.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
||||
@@ -83,13 +167,12 @@ aws4@^1.8.0:
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
|
||||
integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
|
||||
|
||||
azure-arm-compute@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/azure-arm-compute/-/azure-arm-compute-10.0.0.tgz#ce9ba2e4d6dd6b1174c34da2219700a8080f389b"
|
||||
integrity sha512-ehafNtcMKI6c00FT+xhPWPtzhYgHCZ675TUsaJ1FJ2bSpznih5EUrpir/4w519T4zbFBigszhnRK6eBkl78I9g==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
ms-rest "^2.5.0"
|
||||
ms-rest-azure "^2.5.5"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -147,7 +230,7 @@ cluster-key-slot@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
|
||||
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
@@ -215,11 +298,6 @@ denque@^1.1.0, denque@^1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
|
||||
integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
|
||||
|
||||
duplexer@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||
integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
@@ -261,6 +339,11 @@ es-to-primitive@^1.2.1:
|
||||
is-date-object "^1.0.1"
|
||||
is-symbol "^1.0.2"
|
||||
|
||||
event-target-shim@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
@@ -286,11 +369,34 @@ fast-json-stable-stringify@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.3"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
||||
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@^2.5.0:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
|
||||
integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
@@ -300,6 +406,15 @@ form-data@~2.3.2:
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
fs-extra@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
||||
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
@@ -317,6 +432,11 @@ getpass@^0.1.1:
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
version "4.2.6"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
|
||||
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
@@ -371,10 +491,10 @@ ioredis@^4.14.1:
|
||||
redis-parser "^3.0.0"
|
||||
standard-as-callback "^2.0.1"
|
||||
|
||||
is-buffer@^1.1.6:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
ip-regex@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
||||
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
|
||||
|
||||
is-callable@^1.1.4, is-callable@^1.1.5:
|
||||
version "1.2.0"
|
||||
@@ -400,11 +520,6 @@ is-regex@^1.0.5:
|
||||
dependencies:
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
|
||||
|
||||
is-symbol@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
|
||||
@@ -447,6 +562,13 @@ json-stringify-safe@~5.0.1:
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
||||
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
@@ -489,7 +611,7 @@ lodash.flatten@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lodash@^4.14.0, lodash@^4.17.15:
|
||||
lodash@^4.17.15:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
@@ -518,7 +640,7 @@ moment-timezone@^0.5.31:
|
||||
dependencies:
|
||||
moment ">= 2.9.0"
|
||||
|
||||
"moment@>= 2.9.0", moment@^2.21.0, moment@^2.22.2, moment@^2.24.0:
|
||||
"moment@>= 2.9.0", moment@^2.24.0:
|
||||
version "2.26.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
|
||||
integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
|
||||
@@ -574,44 +696,6 @@ mquery@3.2.2:
|
||||
safe-buffer "5.1.2"
|
||||
sliced "1.0.1"
|
||||
|
||||
ms-rest-azure@^2.5.5:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-2.6.0.tgz#2098efec529eecfa0c6e215b69143abcaba12140"
|
||||
integrity sha512-J6386a9krZ4VtU7CRt+Ypgo9RGf8+d3gjMBkH7zbkM4zzkhbbMOYiPRaZ+bHZcfihkKLlktTgA6rjshTjF329A==
|
||||
dependencies:
|
||||
adal-node "^0.1.28"
|
||||
async "2.6.0"
|
||||
moment "^2.22.2"
|
||||
ms-rest "^2.3.2"
|
||||
request "^2.88.0"
|
||||
uuid "^3.2.1"
|
||||
|
||||
ms-rest-azure@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-3.0.0.tgz#54d0341c2aeef7b9f17f2a46258788740b2f0ec5"
|
||||
integrity sha512-cttN01/TtMDB4v3rt/WQ/slgffB6jcUYxcPzcL0VNSB+WFPE1j4y5ICNHMuD1RaNNekCYMI4Pv51BDQ/BXNq7Q==
|
||||
dependencies:
|
||||
adal-node "^0.1.28"
|
||||
async "2.6.0"
|
||||
moment "^2.22.2"
|
||||
ms-rest "^2.3.2"
|
||||
request "^2.88.0"
|
||||
uuid "^3.2.1"
|
||||
|
||||
ms-rest@^2.3.2, ms-rest@^2.5.0:
|
||||
version "2.5.4"
|
||||
resolved "https://registry.yarnpkg.com/ms-rest/-/ms-rest-2.5.4.tgz#57b42299cf302e45d5e1a734220bf7d4a110167a"
|
||||
integrity sha512-VeqCbawxRM6nhw0RKNfj7TWL7SL8PB6MypqwgylXCi+u412uvYoyY/kSmO8n06wyd8nIcnTbYToCmSKFMI1mCg==
|
||||
dependencies:
|
||||
duplexer "^0.1.1"
|
||||
is-buffer "^1.1.6"
|
||||
is-stream "^1.1.0"
|
||||
moment "^2.21.0"
|
||||
request "^2.88.0"
|
||||
through "^2.3.8"
|
||||
tunnel "0.0.5"
|
||||
uuid "^3.2.1"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@@ -707,13 +791,14 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qmi-cloud-common@../qmi-cloud-common:
|
||||
version "1.1.2"
|
||||
version "1.1.6"
|
||||
dependencies:
|
||||
"@azure/arm-compute" "^15.0.0"
|
||||
"@azure/ms-rest-nodeauth" "^3.0.7"
|
||||
"@hapi/boom" "^9.1.0"
|
||||
azure-arm-compute "^10.0.0"
|
||||
axios "^0.21.1"
|
||||
bull "^3.11.0"
|
||||
mongoose "^5.7.4"
|
||||
ms-rest-azure "^3.0.0"
|
||||
nodemailer "^6.4.2"
|
||||
|
||||
qs@~6.5.2:
|
||||
@@ -756,7 +841,7 @@ regexp-clone@1.0.0, regexp-clone@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63"
|
||||
integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==
|
||||
|
||||
"request@>= 2.52.0", request@^2.88.0:
|
||||
"request@>= 2.52.0":
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
@@ -817,6 +902,11 @@ saslprep@^1.0.0:
|
||||
dependencies:
|
||||
sparse-bitfield "^3.0.3"
|
||||
|
||||
sax@>=0.6.0:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
semver@^5.1.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
@@ -905,10 +995,14 @@ string_decoder@~1.1.1:
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||
tough-cookie@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
||||
integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==
|
||||
dependencies:
|
||||
ip-regex "^2.1.0"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
@@ -918,6 +1012,16 @@ tough-cookie@~2.5.0:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tslib@^1.10.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
@@ -925,10 +1029,10 @@ tunnel-agent@^0.6.0:
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tunnel@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.5.tgz#d1532254749ed36620fcd1010865495a1fa9d0ae"
|
||||
integrity sha512-gj5sdqherx4VZKMcBA4vewER7zdK25Td+z1npBqpbDys4eJrLx+SlYjJvq1bDXs2irkuJM5pf8ktaEQVipkrbA==
|
||||
tunnel@0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
@@ -940,6 +1044,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.10.2.tgz#73d6aa3668f3188e4adb0f1943bd12cfd7efaaaf"
|
||||
integrity sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
|
||||
@@ -962,7 +1071,7 @@ util.promisify@^1.0.1:
|
||||
has-symbols "^1.0.1"
|
||||
object.getownpropertydescriptors "^2.1.0"
|
||||
|
||||
uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2, uuid@^3.4.0:
|
||||
uuid@^3.1.0, uuid@^3.3.2, uuid@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
@@ -976,6 +1085,19 @@ verror@1.10.0:
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
xml2js@^0.4.19:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||
dependencies:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~11.0.0"
|
||||
|
||||
xmlbuilder@~11.0.0:
|
||||
version "11.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
|
||||
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
|
||||
|
||||
"xmldom@>= 0.1.x":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a"
|
||||
|
||||
108
qmi-cloud-common/awscli.js
Normal file
@@ -0,0 +1,108 @@
|
||||
const AWS = require("aws-sdk");
|
||||
const db = require("./mongo");
|
||||
const utils = require("./utils");
|
||||
|
||||
|
||||
function _getRgName(provision) {
|
||||
let rgName = provision.scenario.toUpperCase();
|
||||
rgName = rgName.replace(/AZQMI/g, 'QMI');
|
||||
rgName = rgName + "-" + provision._id.toString();
|
||||
return rgName;
|
||||
}
|
||||
|
||||
function _getRegion(provision) {
|
||||
let region = "eu-west-1";
|
||||
if ( provision.deployOpts.location === 'East US') {
|
||||
region = "us-east-1";
|
||||
} else if ( provision.deployOpts.location === 'Southeast Asia' ) {
|
||||
region = "ap-southeast-1";
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
async function deallocate(provision, isSendEmailAfter) {
|
||||
|
||||
let rgName = _getRgName(provision);
|
||||
let region = _getRegion(provision);
|
||||
|
||||
console.log("AWSCLI# Stopping EC2s for resource group: "+rgName);
|
||||
|
||||
var ec2 = new AWS.EC2({apiVersion: '2016-11-15', region: region});
|
||||
var params = {
|
||||
DryRun: false,
|
||||
Filters: [
|
||||
{
|
||||
Name: 'tag:Name',
|
||||
Values: [ `fort-${provision._id}` ]
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
ec2.describeInstances(params, async function (err, data) {
|
||||
if (err) {
|
||||
console.log("AWSCLI# ERROR describing EC2s: "+rgName, err.stack);
|
||||
} else {
|
||||
|
||||
var ec2Ids = data.Reservations[0].Instances.map(ec2=> ec2.InstanceId);
|
||||
console.log("AWSCLI# Stopping EC2s ids", ec2Ids);
|
||||
params = {
|
||||
DryRun: false,
|
||||
InstanceIds: ec2Ids
|
||||
};
|
||||
|
||||
ec2.stopInstances(params, async function(err, data) {
|
||||
if (err) {
|
||||
console.log("AWSCLI# ERROR stopping EC2s: "+rgName, err.stack);
|
||||
} else {
|
||||
console.log("AWSCLI# EC2s stopped!");
|
||||
utils.afterStopVms( provision, isSendEmailAfter );
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function start(provision) {
|
||||
|
||||
let rgName = _getRgName(provision);
|
||||
let region = _getRegion(provision);
|
||||
|
||||
console.log("AWSCLI# Stopping EC2s for resource group: "+rgName);
|
||||
|
||||
var ec2 = new AWS.EC2({apiVersion: '2016-11-15', region: region});
|
||||
var params = {
|
||||
DryRun: false,
|
||||
Filters: [
|
||||
{
|
||||
Name: 'tag:Name',
|
||||
Values: [ `fort-${provision._id}` ]
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
ec2.describeInstances(params, async function (err, data) {
|
||||
if (err) {
|
||||
console.log("AWSCLI# ERROR describing EC2s: "+rgName, err.stack);
|
||||
} else {
|
||||
|
||||
var ec2Ids = data.Reservations[0].Instances.map(ec2=> ec2.InstanceId);
|
||||
console.log("AWSCLI# Starting EC2s ids", ec2Ids);
|
||||
params = {
|
||||
DryRun: false,
|
||||
InstanceIds: ec2Ids
|
||||
};
|
||||
|
||||
ec2.startInstances(params, async function(err, data) {
|
||||
if (err) {
|
||||
console.log("AWSCLI# ERROR starting EC2s: "+rgName, err.stack);
|
||||
} else if (data) {
|
||||
console.log("AWSCLI# EC2s started!");
|
||||
utils.afterStartVms( provision );
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.deallocate = deallocate;
|
||||
module.exports.start = start;
|
||||
@@ -1,7 +1,8 @@
|
||||
const MsRest = require('ms-rest-azure');
|
||||
const computeManagementClient = require('azure-arm-compute');
|
||||
const loginWithVmMSI = require("@azure/ms-rest-nodeauth").loginWithVmMSI;
|
||||
const computeManagementClient = require("@azure/arm-compute").ComputeManagementClient;
|
||||
const dnsManagementClient = require("@azure/arm-dns").DnsManagementClient;
|
||||
const db = require("./mongo");
|
||||
const sendEmail = require("./send-email");
|
||||
const utils = require("./utils");
|
||||
|
||||
const SUBSCRIPTION_ID = "62ebff8f-c40b-41be-9239-252d6c0c8ad9";
|
||||
|
||||
@@ -18,10 +19,22 @@ async function _getClient(scenarioName) {
|
||||
var scenario = await db.scenario.getOne({"name": scenarioName});
|
||||
id = scenario.subscription? scenario.subscription.subsId : SUBSCRIPTION_ID;
|
||||
}
|
||||
var credentials = await MsRest.loginWithMSI({ port: 50342 });
|
||||
var credentials = await loginWithVmMSI({ port: 50342 });
|
||||
//console.log("AzureCLI# authenticated", credentials);
|
||||
return new computeManagementClient(credentials, id);
|
||||
}
|
||||
async function _getDNSClient(scenarioName) {
|
||||
var id = SUBSCRIPTION_ID;
|
||||
if (scenarioName){
|
||||
var scenario = await db.scenario.getOne({"name": scenarioName});
|
||||
id = scenario.subscription? scenario.subscription.subsId : SUBSCRIPTION_ID;
|
||||
}
|
||||
var credentials = await loginWithVmMSI({ port: 50342 });
|
||||
//console.log("AzureCLI# authenticated", credentials);
|
||||
return new dnsManagementClient(credentials, id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function asyncForEach(array, callback) {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
@@ -29,34 +42,32 @@ async function asyncForEach(array, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
async function deallocate(provId, isSendEmailAfter ) {
|
||||
let provision = await db.provision.getById(provId);
|
||||
if ( !provision ) return;
|
||||
async function deallocate(provision, isSendEmailAfter ) {
|
||||
|
||||
let rgName = _getRgName(provision);
|
||||
console.log("AzureCLI# Deallocating VMs for resource group: "+rgName);
|
||||
|
||||
var computeClient = await _getClient(provision.scenario);
|
||||
let finalResult = await computeClient.virtualMachines.list(rgName);
|
||||
if ( finalResult && finalResult.length > 0 ) {
|
||||
db.provision.update(provision._id, {"statusVms": "Stopping"});
|
||||
}
|
||||
|
||||
try {
|
||||
await asyncForEach(finalResult, async function(vm) {
|
||||
await computeClient.virtualMachines.deallocate(rgName, vm.name);
|
||||
});
|
||||
|
||||
let timeRunning = db.utils.getNewTimeRunning(provision);
|
||||
await db.provision.update(provision._id.toString(), {"statusVms": "Stopped", "timeRunning": timeRunning, "stoppedFrom": new Date(), "pendingNextAction": undefined});
|
||||
|
||||
if ( isSendEmailAfter && provision._scenarioDoc ) {
|
||||
await sendEmail.sendVMsStopped(provision, provision._scenarioDoc);
|
||||
}
|
||||
await utils.afterStopVms(provision, isSendEmailAfter);
|
||||
|
||||
console.log("AzureCLI# All VMs DEALLOCATED for resource group: "+rgName);
|
||||
} catch ( error ) {
|
||||
console.log("AzureCLI# ERROR stopping VMs: "+rgName, error);
|
||||
await db.provision.update(provision._id.toString(), {"statusVms": "Running" });
|
||||
}
|
||||
}
|
||||
|
||||
async function start(provId){
|
||||
let provision = await db.provision.getById(provId);
|
||||
if ( !provision ) return;
|
||||
async function start(provision){
|
||||
|
||||
let rgName = _getRgName(provision);
|
||||
console.log("AzureCLI# Starting VMs for resource group: "+rgName);
|
||||
@@ -67,22 +78,36 @@ async function start(provId){
|
||||
if ( finalResult && finalResult.length > 0 ) {
|
||||
db.provision.update(provision._id, {"statusVms": "Starting"});
|
||||
}
|
||||
|
||||
try {
|
||||
await asyncForEach(finalResult, async function(vm) {
|
||||
await computeClient.virtualMachines.start(rgName, vm.name);
|
||||
});
|
||||
let countExtend = db.utils.getNewCountExtend(provision);
|
||||
await db.provision.update(provision._id.toString(), {"statusVms": "Running", "runningFrom": new Date(), "countExtend": countExtend, "pendingNextAction": undefined});
|
||||
console.log("AzureCLI# All VMs RUNNING for resource group: "+rgName);
|
||||
|
||||
await utils.afterStartVms( provision );
|
||||
|
||||
} catch ( error ) {
|
||||
console.log("AzureCLI# ERROR starting VMs: "+rgName, error);
|
||||
await db.provision.update(provision._id.toString(), {"statusVms": "Stopped" });
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function getResourceGroupVms(rgName){
|
||||
var computeClient = await _getClient();
|
||||
let computeClient = await _getClient();
|
||||
return await computeClient.virtualMachines.list(rgName);
|
||||
}
|
||||
|
||||
async function getAllVms(){
|
||||
var computeClient = await _getClient();
|
||||
return await computeClient.virtualMachines.listAll(rgName);
|
||||
let computeClient = await _getClient();
|
||||
console.log("AzureCLI# Retrieving all VMS from subscription");
|
||||
return await computeClient.virtualMachines.listAll();
|
||||
}
|
||||
async function getAllVmsNext(nextLink){
|
||||
let computeClient = await _getClient();
|
||||
console.log("AzureCLI# Retrieving all VMS from subscription (next): " +nextLink);
|
||||
return await computeClient.virtualMachines.listAllNext(nextLink)
|
||||
}
|
||||
|
||||
async function updateVmsTags(provId, tagsEdit) {
|
||||
@@ -94,8 +119,16 @@ async function updateVmsTags(provId, tagsEdit) {
|
||||
let rgName = _getRgName(provision);
|
||||
console.log("AzureCLI# Updating TAGS in VMs for resource group: "+rgName);
|
||||
|
||||
var computeClient = await _getClient(provision.scenario);
|
||||
let finalResult = await computeClient.virtualMachines.list(rgName);
|
||||
|
||||
var computeClient;
|
||||
var finalResult;
|
||||
try {
|
||||
computeClient = await _getClient(provision.scenario);
|
||||
finalResult = await computeClient.virtualMachines.list(rgName);
|
||||
} catch (e2) {
|
||||
console.log(`AzureCLI# ERROR: Resource group '${rgName}' could not be found`, e2);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (finalResult && finalResult.length > 0) {
|
||||
var toDelete = [];
|
||||
@@ -111,6 +144,8 @@ async function updateVmsTags(provId, tagsEdit) {
|
||||
if ( toDelete.length > 0 || toAdd.length > 0 ) {
|
||||
|
||||
await asyncForEach(finalResult, async function(vm) {
|
||||
|
||||
var vmActualTags = JSON.stringify(vm.tags);
|
||||
var tags = vm.tags;
|
||||
toDelete.forEach(t=>{
|
||||
delete tags[t];
|
||||
@@ -120,11 +155,23 @@ async function updateVmsTags(provId, tagsEdit) {
|
||||
});
|
||||
tags["ProvId"] = provision._id.toString();
|
||||
result[vm.name] = tags;
|
||||
console.log(`AzureCLI# VM ${vm.name} new tags: `, tags );
|
||||
computeClient.virtualMachines.update(rgName, vm.name, {"tags": tags} );
|
||||
|
||||
if ( JSON.stringify(tags) !== vmActualTags ) {
|
||||
try {
|
||||
console.log(`AzureCLI# setting new tags to VM ${vm.name} (${rgName})`);
|
||||
await computeClient.virtualMachines.update(rgName, vm.name, {"tags": tags} );
|
||||
} catch (e1) {
|
||||
console.log(`AzureCLI# ERROR setting tags to VM ${vm.name} (${rgName})`, e1);
|
||||
}
|
||||
} else {
|
||||
console.log(`AzureCLI# Same tags, no need to update tags for VM ${vm.name} (${rgName})`);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
//db.event.add({ user: provision.user._id, provision: provision._id, type: 'provision.vms-tags-update' });
|
||||
|
||||
return result;
|
||||
|
||||
} else {
|
||||
@@ -132,8 +179,53 @@ async function updateVmsTags(provId, tagsEdit) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* DNS Records
|
||||
*/
|
||||
|
||||
const DNS_RESOURCE_GROUP = "QMI-Infra-DNS";
|
||||
const DNS_ZONE_NAME = "qmi.qlik-poc.com";
|
||||
|
||||
async function getDNSRecords(type = "CNAME") {
|
||||
let dnsClient = await _getDNSClient();
|
||||
console.log(`AzureCLI# Retrieving '${type}' DNS records`);
|
||||
return await dnsClient.recordSets.listByType(DNS_RESOURCE_GROUP, DNS_ZONE_NAME, type);
|
||||
}
|
||||
|
||||
async function createDNSRecord(provision, cname, type = "CNAME"){
|
||||
|
||||
if ( !provision ) return;
|
||||
|
||||
let rgName = _getRgName(provision).toLowerCase();
|
||||
|
||||
let dnsClient = await _getDNSClient();
|
||||
console.log(`AzureCLI# Creating '${type}' DNS record: ${rgName}.${DNS_ZONE_NAME} --> ${cname}`);
|
||||
let parameters = {
|
||||
"cnameRecord": {
|
||||
"cname": cname
|
||||
},
|
||||
"tTL": 60
|
||||
};
|
||||
return await dnsClient.recordSets.createOrUpdate(DNS_RESOURCE_GROUP, DNS_ZONE_NAME, rgName, type, parameters );
|
||||
}
|
||||
|
||||
async function deleteDNSRecord(provision, type = "CNAME"){
|
||||
|
||||
if ( !provision ) return;
|
||||
|
||||
let rgName = _getRgName(provision).toLowerCase();
|
||||
let dnsClient = await _getDNSClient();
|
||||
console.log(`AzureCLI# Deleting '${type}' DNS record: ${rgName}.${DNS_ZONE_NAME}`);
|
||||
return await dnsClient.recordSets.deleteMethod(DNS_RESOURCE_GROUP, DNS_ZONE_NAME, rgName, type );
|
||||
}
|
||||
|
||||
module.exports.start = start;
|
||||
module.exports.deallocate = deallocate;
|
||||
module.exports.getResourceGroupVms = getResourceGroupVms;
|
||||
module.exports.getAllVms = getAllVms;
|
||||
module.exports.getAllVmsNext = getAllVmsNext;
|
||||
module.exports.updateVmsTags = updateVmsTags;
|
||||
module.exports.getDNSRecords = getDNSRecords;
|
||||
module.exports.createDNSRecord = createDNSRecord;
|
||||
module.exports.deleteDNSRecord = deleteDNSRecord
|
||||
|
||||
85
qmi-cloud-common/barracuda.js
Normal file
@@ -0,0 +1,85 @@
|
||||
const BarracudaAPI = require('barracuda-api');
|
||||
const azurecli = require('./azurecli');
|
||||
const db = require('./mongo');
|
||||
|
||||
const DOMAIN = "qmi.qlik-poc.com";
|
||||
|
||||
async function createApp(prov) {
|
||||
|
||||
if ( !prov._scenarioDoc.barracudaTemplate || prov._scenarioDoc.barracudaTemplate === 'qs-only-443' ) {
|
||||
_createApp(prov, "443", "HTTPS");
|
||||
} else if ( prov._scenarioDoc.barracudaTemplate === 'qdc-only-8443' ) {
|
||||
_createApp(prov, "8443", "HTTPS");
|
||||
} else if (prov._scenarioDoc.barracudaTemplate) {
|
||||
var spl = prov._scenarioDoc.barracudaTemplate.split("-");
|
||||
_createApp(prov, spl[0], spl[1]);
|
||||
}
|
||||
}
|
||||
|
||||
async function _createApp(provision, backendPort, backendType) {
|
||||
|
||||
|
||||
if ( !provision || !provision.barracudaAzureFqdn ) {
|
||||
console.log(`Barracuda# Provision does not exist or does not have a barracudaAzureFqdn value. Do nothing.`);
|
||||
return;
|
||||
}
|
||||
|
||||
let appName = provision.scenario.toLowerCase();
|
||||
appName = appName.replace(/azqmi/g, 'qmi');
|
||||
appName = `${appName}-${provision._id}`
|
||||
|
||||
console.log(`Barracuda# Creating Barracuda App for provision (${appName})`);
|
||||
|
||||
const client = new BarracudaAPI.QlikSenseNPrintingApp();
|
||||
client.create(appName, `${appName}.${DOMAIN}`, provision.barracudaAzureFqdn, backendPort, backendType).then(function(result) {
|
||||
let bApp = result.app;
|
||||
console.log("Barracuda# Barracuda App created! ID: "+ bApp.id);
|
||||
let cname = bApp.waas_services && bApp.waas_services.length? bApp.waas_services[0].cname : null;
|
||||
db.provision.update(provision._id, {"barracudaAppId": bApp.id, "barracudaAppCname":cname});
|
||||
|
||||
console.log("Barracuda# Creating DNS record in Azure: "+cname);
|
||||
azurecli.createDNSRecord(provision, cname);
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'provision.is-public' });
|
||||
|
||||
}).catch(function(err){
|
||||
console.log("Barracuda# Error creating Barracuda App", err);
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteApp(provision) {
|
||||
|
||||
|
||||
if ( !provision || !provision.barracudaAppId ) {
|
||||
console.log(`Barracuda# Provision does not exist or does not have a barracudaAppId value. Do nothing.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Barracuda# Deleting DNS record in Azure and Barracuda App ID (${provision.barracudaAppId}) for provision (${provision._id})`);
|
||||
|
||||
azurecli.deleteDNSRecord(provision);
|
||||
const client = new BarracudaAPI.QlikSenseNPrintingApp();
|
||||
client.delete(provision.barracudaAppId).then(function() {
|
||||
console.log("Barracuda# Barracuda App deleted! ID: "+ provision.barracudaAppId);
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'provision.is-private' });
|
||||
}).catch(function(err){
|
||||
console.log("Barracuda# Error deleting Barracuda App", err);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async function getApp(provision) {
|
||||
|
||||
if ( !provision || !provision.barracudaAppId ) {
|
||||
console.log(`Barracuda# Provision does not exist or does not have a barracudaAppId value. Do nothing.`);
|
||||
return;
|
||||
}
|
||||
const client = new BarracudaAPI.QlikSenseNPrintingApp();
|
||||
return await client.getDetails(provision.barracudaAppId);
|
||||
|
||||
}
|
||||
|
||||
module.exports.getApp = getApp;
|
||||
module.exports.createApp = createApp;
|
||||
module.exports.deleteApp = deleteApp;
|
||||
38
qmi-cloud-common/cli.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const awscli = require("./awscli");
|
||||
const azurecli = require("./azurecli");
|
||||
const db = require("./mongo");
|
||||
|
||||
|
||||
async function deallocate(provId, isSendEmailAfter ) {
|
||||
let provision = await db.provision.getById(provId);
|
||||
if ( !provision ) return;
|
||||
|
||||
azurecli.deallocate(provision, isSendEmailAfter);
|
||||
|
||||
if (provision.scenario === 'azqmi-fort'){
|
||||
awscli.stop(provision, isSendEmailAfter);
|
||||
} else {
|
||||
azurecli.deallocate(provision, isSendEmailAfter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function start(provId){
|
||||
|
||||
let provision = await db.provision.getById(provId);
|
||||
if ( !provision ) return;
|
||||
|
||||
if (provision.scenario === 'azqmi-fort'){
|
||||
awscli.start(provision);
|
||||
} else {
|
||||
azurecli.start(provision);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateVmsTags(provId, tagsEdit) {
|
||||
azurecli.updateVmsTags(provId, tagsEdit);
|
||||
}
|
||||
|
||||
module.exports.deallocate = deallocate;
|
||||
module.exports.start = start;
|
||||
module.exports.updateVmsTags = updateVmsTags;
|
||||
4
qmi-cloud-common/config.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
DOCKERIMAGE_TERRAFORM: "qlikgear/terraform:0.13.4",
|
||||
PROVISION_VERSION: 20201124
|
||||
}
|
||||
31
qmi-cloud-common/models/Event.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const mongoose = require('mongoose');
|
||||
mongoose.set('useFindAndModify', false);
|
||||
const crypto = require("crypto");
|
||||
//mongoose.set('debug', true)
|
||||
|
||||
|
||||
const schema = new mongoose.Schema({
|
||||
created: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
index : true
|
||||
},
|
||||
user: {
|
||||
type: mongoose.Types.ObjectId,
|
||||
ref: 'User',
|
||||
index : true
|
||||
},
|
||||
provision: {
|
||||
type: mongoose.Types.ObjectId,
|
||||
ref: 'Provision'
|
||||
},
|
||||
type: {
|
||||
type: String
|
||||
},
|
||||
message: {
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = mongoose.model('Event', schema)
|
||||
@@ -4,7 +4,8 @@ mongoose.set('useFindAndModify', false);
|
||||
|
||||
const provisionSchema = new mongoose.Schema({
|
||||
user: {
|
||||
type: mongoose.Types.ObjectId, ref: 'User',
|
||||
type: mongoose.Types.ObjectId,
|
||||
ref: 'User',
|
||||
index: true
|
||||
},
|
||||
created: {
|
||||
@@ -38,6 +39,15 @@ const provisionSchema = new mongoose.Schema({
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
barracudaAppId: {
|
||||
type: String
|
||||
},
|
||||
barracudaAppCname: {
|
||||
type: String
|
||||
},
|
||||
barracudaAzureFqdn: {
|
||||
type: String
|
||||
},
|
||||
isDestroyed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
@@ -66,6 +76,12 @@ const provisionSchema = new mongoose.Schema({
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
startDateOnSchedule: {
|
||||
type: Date
|
||||
},
|
||||
endDateOnSchedule: {
|
||||
type: Date
|
||||
},
|
||||
countExtend: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@@ -82,8 +98,10 @@ const provisionSchema = new mongoose.Schema({
|
||||
ref: "Subscription"
|
||||
},
|
||||
terraformImage: {
|
||||
type: String,
|
||||
default: "qlikgear/terraform:0.13.4"
|
||||
type: String
|
||||
},
|
||||
version: {
|
||||
type: Number
|
||||
}
|
||||
},{
|
||||
toObject: {virtuals:true},
|
||||
|
||||
@@ -50,6 +50,9 @@ const scenarioSchema = new mongoose.Schema({
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
gitBranch: {
|
||||
type: String
|
||||
},
|
||||
description: String,
|
||||
availableProductVersions: Array,
|
||||
productVersionDefault: String,
|
||||
@@ -65,7 +68,30 @@ const scenarioSchema = new mongoose.Schema({
|
||||
}],
|
||||
labels: [{
|
||||
type: String
|
||||
}]
|
||||
}],
|
||||
allowedUsers: [{
|
||||
type: mongoose.Types.ObjectId,
|
||||
ref: 'User',
|
||||
required: true
|
||||
}],
|
||||
support: [{
|
||||
type: String
|
||||
}],
|
||||
barracudaTemplate: {
|
||||
type: String
|
||||
},
|
||||
allowedInnactiveDays: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
allowed24x7RunningDays: {
|
||||
type: Number,
|
||||
default: 7
|
||||
},
|
||||
allowedOnScheduleRunningDays: {
|
||||
type: Number,
|
||||
default: 4
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@ const sc = new mongoose.Schema({
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
onScheduleRenewed: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
localeShutdownTime: {
|
||||
type: String
|
||||
},
|
||||
|
||||
@@ -42,6 +42,7 @@ const VmType = require('./models/VmType');
|
||||
const ApiKey = require('./models/ApiKey');
|
||||
const Notification = require('./models/Notification');
|
||||
const Subscription = require('./models/Subscription');
|
||||
const Event = require('./models/Event');
|
||||
|
||||
|
||||
const getNewCountExtend = function(provision) {
|
||||
@@ -128,8 +129,15 @@ const getPage = async ( model, filter, page, populates, select ) => {
|
||||
const get = async (model, filter, select, skip, limit, populates, reply) => {
|
||||
var sort = {};
|
||||
var modelAttributes = Object.keys(model.schema.tree);
|
||||
|
||||
if ( model === Scenario ) {
|
||||
if ( modelAttributes.indexOf("updated") !== -1) {
|
||||
sort.updated = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( modelAttributes.indexOf("created") !== -1) {
|
||||
sort = {created: -1};
|
||||
sort.created = -1;
|
||||
}
|
||||
try {
|
||||
var exec = model.find(filter, select).sort(sort);
|
||||
@@ -158,7 +166,7 @@ const get = async (model, filter, select, skip, limit, populates, reply) => {
|
||||
}
|
||||
|
||||
if ( model = Scenario ) {
|
||||
exec = exec.populate('subscription').populate('deployOpts');
|
||||
exec = exec.populate('subscription').populate('deployOpts').populate('allowedUsers');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +197,7 @@ const getById = async (model, id, reply) => {
|
||||
exec = exec.populate('user');
|
||||
}
|
||||
if ( model = Scenario ) {
|
||||
exec = exec.populate('subscription').populate('deployOpts');
|
||||
exec = exec.populate('subscription').populate('deployOpts').populate('allowedUsers');
|
||||
}
|
||||
const entity = await exec;
|
||||
return entity;
|
||||
@@ -208,7 +216,7 @@ const getOne = async (model, filter, reply) => {
|
||||
exec = exec.populate('user');
|
||||
}
|
||||
if ( model = Scenario ) {
|
||||
exec = exec.populate('subscription').populate('deployOpts');
|
||||
exec = exec.populate('subscription').populate('deployOpts').populate('allowedUsers');
|
||||
}
|
||||
const entity = await exec;
|
||||
return entity;
|
||||
@@ -248,6 +256,31 @@ const update = async (model, id, body, reply) => {
|
||||
}
|
||||
};
|
||||
|
||||
const updateMany = async (model, filter, body, reply) => {
|
||||
try {
|
||||
const { ...updateData } = body;
|
||||
|
||||
updateData.updated = new Date();
|
||||
|
||||
var exec = model.updateMany(filter, updateData);
|
||||
|
||||
if ( model === Provision ) {
|
||||
exec = exec.populate('user').populate('destroy').populate('_scenarioDoc').populate("schedule").populate('deployOpts');
|
||||
}
|
||||
if ( model === ApiKey ) {
|
||||
exec = exec.populate('user');
|
||||
}
|
||||
if ( model = Scenario ) {
|
||||
exec = exec.populate('subscription').populate('deployOpts');
|
||||
}
|
||||
|
||||
return await exec;
|
||||
|
||||
} catch (err) {
|
||||
throw boom.boomify(err)
|
||||
}
|
||||
};
|
||||
|
||||
const del = async (model, id, reply) => {
|
||||
try {
|
||||
const entity = await model.findByIdAndRemove(id)
|
||||
@@ -257,6 +290,15 @@ const del = async (model, id, reply) => {
|
||||
}
|
||||
}
|
||||
|
||||
const count = async (model, filter, reply) => {
|
||||
try {
|
||||
var totalDocs = await model.countDocuments(filter);
|
||||
return totalDocs;
|
||||
} catch (err) {
|
||||
throw boom.boomify(err)
|
||||
}
|
||||
}
|
||||
|
||||
function _m(model) {
|
||||
return {
|
||||
get: async (filter, select, skip, limit, populates, reply) => {
|
||||
@@ -277,8 +319,14 @@ function _m(model) {
|
||||
update: async (id, data, reply) => {
|
||||
return update(model, id, data, reply);
|
||||
},
|
||||
updateMany: async(filter, data, reply) => {
|
||||
return updateMany(model, filter, data, reply);
|
||||
},
|
||||
del: async (id, reply) => {
|
||||
return del(model, id, reply);
|
||||
},
|
||||
count: async (filter, reply) => {
|
||||
return count(model, filter, reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,6 +341,7 @@ module.exports = {
|
||||
apiKey: _m(ApiKey),
|
||||
notification: _m(Notification),
|
||||
subscription: _m(Subscription),
|
||||
event: _m(Event),
|
||||
user: _m(User),
|
||||
utils: {
|
||||
getNewTimeRunning: getNewTimeRunning,
|
||||
@@ -308,7 +357,8 @@ module.exports = {
|
||||
VmType: VmType,
|
||||
Notification: Notification,
|
||||
ApiKey: ApiKey,
|
||||
Subscription: Subscription
|
||||
Subscription: Subscription,
|
||||
Event: Event
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
1315
qmi-cloud-common/package-lock.json
generated
Normal file
@@ -1,12 +1,17 @@
|
||||
{
|
||||
"name": "qmi-cloud-common",
|
||||
"version": "1.1.5",
|
||||
"version": "1.1.6",
|
||||
"dependencies": {
|
||||
"@azure/arm-compute": "^15.0.0",
|
||||
"@azure/arm-dns": "^4.0.0",
|
||||
"@azure/ms-rest-nodeauth": "^3.0.7",
|
||||
"@hapi/boom": "^9.1.0",
|
||||
"aws-sdk": "^2.942.0",
|
||||
"axios": "^0.21.1",
|
||||
"barracuda-api": "https://gitlab.com/qlik_gear/barracuda-api-node.git#0.0.10",
|
||||
"bull": "^3.11.0",
|
||||
"mongoose": "^5.7.4",
|
||||
"nodemailer": "^6.4.2",
|
||||
"azure-arm-compute": "^10.0.0",
|
||||
"ms-rest-azure": "^3.0.0",
|
||||
"bull": "^3.11.0"
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,27 @@ const Queue = require('bull');
|
||||
export const TF_APPLY_QUEUE = 'TF_APPLY_QUEUE';
|
||||
export const TF_DESTROY_QUEUE = 'TF_DESTROY_QUEUE';
|
||||
export const TF_APPLY_QSEOK_QUEUE = 'TF_APPLY_QSEOK_QUEUE';
|
||||
export const STOP_CONTAINER_QUEUE = 'STOP_CONTAINER_QUEUE';
|
||||
|
||||
|
||||
var terraformApplyQueue = new Queue(TF_APPLY_QUEUE, process.env.REDIS_URL);
|
||||
var terraformDestroyQueue = new Queue(TF_DESTROY_QUEUE, process.env.REDIS_URL);
|
||||
var terraformApplyQseokQueue = new Queue(TF_APPLY_QSEOK_QUEUE, process.env.REDIS_URL);
|
||||
|
||||
var stopContainerQueue = new Queue(STOP_CONTAINER_QUEUE, process.env.REDIS_URL);
|
||||
|
||||
|
||||
export const queues = {
|
||||
[TF_APPLY_QUEUE]: terraformApplyQueue,
|
||||
[TF_DESTROY_QUEUE]: terraformDestroyQueue,
|
||||
[TF_APPLY_QSEOK_QUEUE]: terraformApplyQseokQueue
|
||||
[TF_APPLY_QSEOK_QUEUE]: terraformApplyQseokQueue,
|
||||
[STOP_CONTAINER_QUEUE]: stopContainerQueue
|
||||
};
|
||||
|
||||
|
||||
for (let key in queues) {
|
||||
queues[key].on('completed', function(job, result) {
|
||||
//console.log(`Queues# Job ${job.id} completed! Result`, result);
|
||||
console.log(`Queues# Job ${job.id} completed!`);
|
||||
console.log(`Queue ${key}# Job ${job.id} completed!`);
|
||||
});
|
||||
|
||||
|
||||
@@ -31,13 +33,13 @@ for (let key in queues) {
|
||||
});
|
||||
|
||||
queues[key].on('waiting', function(jobId){
|
||||
console.log(`Queues# Job ${jobId} is waiting...`);
|
||||
console.log(`Queue ${key}# Job ${jobId} is waiting...`);
|
||||
// A Job is waiting to be processed as soon as a worker is idling.
|
||||
});
|
||||
|
||||
queues[key].on('active', function(job, jobPromise){
|
||||
// A job has started. You can use `jobPromise.cancel()`` to abort it.
|
||||
console.log(`Queues# Job ${job.id} is now active`);
|
||||
console.log(`Queue ${key}# Job ${job.id} is now active`);
|
||||
});
|
||||
|
||||
queues[key].on('stalled', function(job){
|
||||
@@ -47,12 +49,12 @@ for (let key in queues) {
|
||||
|
||||
queues[key].on('progress', function(job, progress){
|
||||
// A job's progress was updated!
|
||||
console.log(`Queues# Job ${job.id} is ${progress * 100}% ready!`);
|
||||
console.log(`Queue ${key}# Job ${job.id} is ${progress * 100}% ready!`);
|
||||
});
|
||||
|
||||
queues[key].on('failed', function(job, err){
|
||||
// A job failed with reason `err`!
|
||||
console.log(`Queues# Job ${job.id} has failed:`, err);
|
||||
console.log(`Queue ${key}# Job ${job.id} has failed:`, err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
278
qmi-cloud-common/send-email copy.js
Normal file
@@ -0,0 +1,278 @@
|
||||
'use strict';
|
||||
const nodemailer = require('nodemailer');
|
||||
const FROM = '"Qlik" <no-reply@qlik.com>';
|
||||
var transporter;
|
||||
|
||||
const HOSTNAME_URL = process.env.HOSTNAME_URL || "https://qmicloud.qliktech.com";
|
||||
const FOOTER = `<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="${HOSTNAME_URL}">${HOSTNAME_URL}</a></p>
|
||||
</div>`;
|
||||
|
||||
if ( process.env.GMAIL_USERNAME && process.env.GMAIL_PASSWORD ) {
|
||||
//GMAIL
|
||||
transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
port: 587,
|
||||
secure: false,
|
||||
auth: {
|
||||
user: process.env.GMAIL_USERNAME,
|
||||
pass: process.env.GMAIL_PASSWORD
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//QLIK
|
||||
transporter = nodemailer.createTransport({
|
||||
host: 'smtp.qliktech.com',
|
||||
port: 587,
|
||||
secure: false, // true for 465, false for other ports
|
||||
});
|
||||
}
|
||||
|
||||
async function _doSend(to, subject, htmlText) {
|
||||
// send mail with defined transport object
|
||||
|
||||
try {
|
||||
|
||||
let info = await transporter.sendMail( {
|
||||
from: FROM, // sender address
|
||||
to: to, // list of receivers
|
||||
subject: subject, // Subject line
|
||||
text: subject, // plain text body
|
||||
html: htmlText // html body
|
||||
} );
|
||||
|
||||
console.log('SendEmail# message id ('+info.messageId+') sent to: ' + to);
|
||||
|
||||
return info;
|
||||
} catch (err) {
|
||||
|
||||
console.log('SendEmail# ERROR!! -> could not send email to: ' + to);
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
function _getCommonDetails(provision, scenario){
|
||||
var description = decodeURI(scenario.description);
|
||||
var externalAccess = provision.isExternalAccess? 'Yes' : 'No';
|
||||
var schedule = "";
|
||||
if ( !provision.schedule || provision.schedule.is24x7 ) {
|
||||
schedule = "24x7";
|
||||
} else if ( provision.schedule && !provision.schedule.is24x7 ) {
|
||||
schedule = `from ${provision.schedule.localeStartupTime}h until ${provision.schedule.localeShutdownTime}h (${provision.schedule.localTimezone})`;
|
||||
}
|
||||
return `<div style="color:#404040;font-size:18px;margin:20px 0px">
|
||||
<p style="margin:0px">Provision information:</p>
|
||||
</div>
|
||||
<div>
|
||||
<span style="color:#404040">ID: </span> ${provision._id}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color:#404040">VMs Running schedule: </span> ${schedule}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color:#404040">Purpose: </span> ${provision.description}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color:#404040">Scenario: </span> ${scenario.title}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color:#404040">With external access: </span> ${externalAccess}
|
||||
</div>
|
||||
<div>
|
||||
<span style="color:#404040">Description: </span> ${description}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function getHtmlScenarioDestroyIn24( provision, scenario, period, warningDays) {
|
||||
var common = _getCommonDetails(provision,scenario);
|
||||
return`<div style="width:600px;color:black!important;font-family:'Source Sans Pro',sans-serif;padding:50px">
|
||||
<div style="background-color:white;height:100%;padding:20px 10px">
|
||||
<div style="color:#404040;font-size:34px;text-align:center;margin:20px">
|
||||
<p style="margin:0px">QMI Cloud</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:22px;margin:20px 0px 40px 0px">
|
||||
<p style="margin:0px">Provision '${scenario.title}' inactive more than ${period} days</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:18px;margin:10px 0px">
|
||||
<p style="margin:0px;color: #FF2020">This scenario will be automatically DESTROYED in ${(warningDays*24)} hours.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">If you don't want this to happen, you've got ${(warningDays*24)} hours (from when this email was sent) as a grace period to get back at 'Running' status this provision.</p>
|
||||
</div>
|
||||
${common}
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
function getHtmlScenarioVMsStopped( provision, scenario) {
|
||||
var common = _getCommonDetails(provision,scenario);
|
||||
return `<div style="width:600px;color:black!important;font-family:'Source Sans Pro',sans-serif;padding:50px">
|
||||
<div style="background-color:white;height:100%;padding:20px 10px">
|
||||
<div style="color:#404040;font-size:34px;text-align:center;margin:20px">
|
||||
<p style="margin:0px">QMI Cloud</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:22px;margin:20px 0px 40px 0px">
|
||||
<p style="margin:0px">Provision '${scenario.title}'</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:18px;margin:10px 0px">
|
||||
<p style="margin:0px;color: #FF2020">All VMs for this provision <b>stopped</b> automatically.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">You can start them up again from <a href="${HOSTNAME_URL}">${HOSTNAME_URL}</a></p>
|
||||
</div>
|
||||
${common}
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function getHtmlScenarioWillStopIn24( provision, scenario, period, warningDays ) {
|
||||
var common = _getCommonDetails(provision,scenario);
|
||||
return`<div style="width:600px;color:black!important;font-family:'Source Sans Pro',sans-serif;padding:50px">
|
||||
<div style="background-color:white;height:100%;padding:20px 10px">
|
||||
<div style="color:#404040;font-size:34px;text-align:center;margin:20px">
|
||||
<p style="margin:0px">QMI Cloud</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:22px;margin:20px 0px 40px 0px">
|
||||
<p style="margin:0px">Provision '${scenario.title}' - VMs running for ${period} days</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:18px;margin:10px 0px">
|
||||
<p style="margin:0px;color: #FF2020">This scenario will automatically stop its VMs in ${warningDays*24} hours.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:18px;margin:20px 0px 10px 0px">
|
||||
<p style="margin:0px;color: #FF2020">Take action and extend the period ${(period+warningDays)} extra days.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">If you don't want the VMs to automatically stop, you've got ${warningDays*24} hours (from when this email was sent) as a grace period to extend this scenario's <b style="color: #009845">Running</b> VMs for ${(period+warningDays)} extra days.</p>
|
||||
</div>
|
||||
${common}
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
function getHtmlNewProvision(provision, scenario) {
|
||||
var htmlint;
|
||||
if ( provision && provision.outputs ) {
|
||||
htmlint = `<div style="color:#404040;font-size:18px;padding: 10px 0px;">Connection resources</div>`;
|
||||
} else {
|
||||
htmlint = "";
|
||||
}
|
||||
for (let key in provision.outputs) {
|
||||
htmlint += `<div>
|
||||
<span style="color:#404040">${key}</span>
|
||||
<pre style="color:#404040;">${provision.outputs[key]}</pre>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
var common = _getCommonDetails(provision, scenario);
|
||||
|
||||
return `<div style="width:600px;color:black!important;font-family:'Source Sans Pro',sans-serif;padding:50px">
|
||||
<div style="background-color:white;height:100%;padding:20px 10px">
|
||||
<div style="color:#404040;font-size:34px;text-align:center;margin:20px">
|
||||
<p style="margin:0px">QMI Cloud</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:22px;margin:20px 0px">
|
||||
<p style="margin:0px">Scenario '${scenario.title}' successfully provisioned!</p>
|
||||
</div>
|
||||
|
||||
${common}
|
||||
|
||||
<div style="margin: 30px 0px;">
|
||||
${htmlint}
|
||||
</div>
|
||||
${FOOTER}
|
||||
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function getHtmlErrorProvision(provision, scenario) {
|
||||
var common = _getCommonDetails(provision, scenario);
|
||||
return`<div style="width:600px;color:black!important;font-family:'Source Sans Pro',sans-serif;padding:50px">
|
||||
<div style="background-color:white;height:100%;padding:20px 10px">
|
||||
<div style="color:#404040;font-size:34px;text-align:center;margin:20px">
|
||||
<p style="margin:0px">QMI Cloud</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:20px;margin:20px 0px">
|
||||
<p style="margin:0px;color: #FF2020">Oops! Something didn't work.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:20px;margin:20px 0px 50px 0px">
|
||||
<p style="margin:0px">Scenario '${scenario.title}' failed during provision.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Please, follow these steps:</p>
|
||||
<ul>
|
||||
<li>Reach out the person responsible for this scenario for support.</li>
|
||||
<li>As soon as it's possible, consider destroy this provision since it's taking valuable cloud resources which might imply relevant cost.</li>
|
||||
</ul>
|
||||
</div>
|
||||
${common}
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function getHtmlDestroyProvision(provision, scenario) {
|
||||
var common = _getCommonDetails(provision, scenario);
|
||||
return`<div style="width:600px;color:black!important;font-family:'Source Sans Pro',sans-serif;padding:50px">
|
||||
<div style="background-color:white;height:100%;padding:20px 10px">
|
||||
<div style="color:#404040;font-size:34px;text-align:center;margin:20px">
|
||||
<p style="margin:0px">QMI Cloud</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:20px;margin:40px 0px">
|
||||
<p style="margin:0px">Scenario '${scenario.title}' successfully destroyed!</p>
|
||||
</div>
|
||||
${common}
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
// async..await is not allowed in global scope, must use a wrapper
|
||||
async function sendProvisionSuccess( provision, scenario ) {
|
||||
const htmlText = getHtmlNewProvision(provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision finished successfully', htmlText);
|
||||
}
|
||||
|
||||
async function sendProvisionError(provision, scenario ) {
|
||||
const htmlText = getHtmlErrorProvision(provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision with errors', htmlText);
|
||||
}
|
||||
|
||||
async function sendDestroyedSuccess(provision, scenario ) {
|
||||
|
||||
const htmlText = getHtmlDestroyProvision(provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision destroyed successfully', htmlText);
|
||||
|
||||
}
|
||||
|
||||
async function sendWillStopIn24( provision, scenario, period, warningDays ) {
|
||||
|
||||
const htmlText = getHtmlScenarioWillStopIn24( provision, scenario, period, warningDays);
|
||||
await _doSend(provision.user.upn, `QMI Cloud - VMs will stop in ${warningDays*24} hours`, htmlText);
|
||||
|
||||
}
|
||||
|
||||
async function sendWillDestroyIn24( provision, scenario, period, warningDays ) {
|
||||
|
||||
const htmlText = getHtmlScenarioDestroyIn24( provision, scenario, period, warningDays);
|
||||
await _doSend(provision.user.upn, `QMI Cloud - Provision will destroy in ${(warningDays*24)} hours`, htmlText);
|
||||
}
|
||||
|
||||
async function sendVMsStopped( provision, scenario ) {
|
||||
const htmlText = getHtmlScenarioVMsStopped( provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - VMs stopped automatically', htmlText);
|
||||
}
|
||||
|
||||
module.exports.sendProvisionSuccess = sendProvisionSuccess;
|
||||
module.exports.sendProvisionError = sendProvisionError;
|
||||
module.exports.sendDestroyedSuccess = sendDestroyedSuccess;
|
||||
module.exports.sendWillStopIn24 = sendWillStopIn24;
|
||||
module.exports.sendVMsStopped = sendVMsStopped;
|
||||
module.exports.sendWillDestroyIn24 = sendWillDestroyIn24;
|
||||
module.exports._doSend = _doSend;
|
||||
|
||||
|
||||
@@ -1,39 +1,35 @@
|
||||
'use strict';
|
||||
const nodemailer = require('nodemailer');
|
||||
const FROM = '"Qlik" <no-reply@qlik.com>';
|
||||
var transporter;
|
||||
const axios = require('axios');
|
||||
const https = require("https");
|
||||
const SMTP_EMAIL_SENDER = process.env.SMTP_EMAIL_SENDER;
|
||||
|
||||
const HOSTNAME_URL = process.env.HOSTNAME_URL || "https://qmicloud.qliktech.com";
|
||||
const FOOTER = `<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="${HOSTNAME_URL}">${HOSTNAME_URL}</a></p>
|
||||
</div>`;
|
||||
|
||||
if ( process.env.GMAIL_USERNAME && process.env.GMAIL_PASSWORD ) {
|
||||
//GMAIL
|
||||
transporter = nodemailer.createTransport({
|
||||
service: 'gmail',
|
||||
port: 587,
|
||||
secure: false,
|
||||
auth: {
|
||||
user: process.env.GMAIL_USERNAME,
|
||||
pass: process.env.GMAIL_PASSWORD
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//QLIK
|
||||
transporter = nodemailer.createTransport({
|
||||
host: 'smtp.qliktech.com',
|
||||
port: 587,
|
||||
secure: false, // true for 465, false for other ports
|
||||
});
|
||||
}
|
||||
|
||||
async function _doSend(to, subject, htmlText) {
|
||||
// send mail with defined transport object
|
||||
let info = await transporter.sendMail( {
|
||||
from: FROM, // sender address
|
||||
to: to, // list of receivers
|
||||
subject: subject, // Subject line
|
||||
text: subject, // plain text body
|
||||
html: htmlText // html body
|
||||
try {
|
||||
var body = {
|
||||
"to": to,
|
||||
"subject": subject,
|
||||
"html": htmlText
|
||||
};
|
||||
await axios({
|
||||
url: SMTP_EMAIL_SENDER,
|
||||
method: "post",
|
||||
data: body,
|
||||
httpsAgent: new https.Agent({
|
||||
rejectUnauthorized: false
|
||||
})
|
||||
});
|
||||
console.log('SendEmail (Qlik SMTP)# message sent to: ' + to);
|
||||
|
||||
console.log('SendEmail# message id ('+info.messageId+') sent to: ' + to);
|
||||
} catch (err) {
|
||||
// Handle Error Here
|
||||
console.log("SendEmail (Qlik SMTP) _doSend error: could not send the email to: " +to);
|
||||
}
|
||||
}
|
||||
|
||||
function _getCommonDetails(provision, scenario){
|
||||
@@ -85,9 +81,7 @@ function getHtmlScenarioDestroyIn24( provision, scenario, period, warningDays) {
|
||||
<p style="margin:0px">If you don't want this to happen, you've got ${(warningDays*24)} hours (from when this email was sent) as a grace period to get back at 'Running' status this provision.</p>
|
||||
</div>
|
||||
${common}
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
</div>
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -107,12 +101,10 @@ function getHtmlScenarioVMsStopped( provision, scenario) {
|
||||
<p style="margin:0px;color: #FF2020">All VMs for this provision <b>stopped</b> automatically.</p>
|
||||
</div>
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">You can start them up again from <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
<p style="margin:0px">You can start them up again from <a href="${HOSTNAME_URL}">${HOSTNAME_URL}</a></p>
|
||||
</div>
|
||||
${common}
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
</div>
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -137,9 +129,7 @@ function getHtmlScenarioWillStopIn24( provision, scenario, period, warningDays )
|
||||
<p style="margin:0px">If you don't want the VMs to automatically stop, you've got ${warningDays*24} hours (from when this email was sent) as a grace period to extend this scenario's <b style="color: #009845">Running</b> VMs for ${(period+warningDays)} extra days.</p>
|
||||
</div>
|
||||
${common}
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
</div>
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -173,9 +163,7 @@ function getHtmlNewProvision(provision, scenario) {
|
||||
<div style="margin: 30px 0px;">
|
||||
${htmlint}
|
||||
</div>
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
</div>
|
||||
${FOOTER}
|
||||
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -194,10 +182,15 @@ function getHtmlErrorProvision(provision, scenario) {
|
||||
<div style="color:#404040;font-size:20px;margin:20px 0px 50px 0px">
|
||||
<p style="margin:0px">Scenario '${scenario.title}' failed during provision.</p>
|
||||
</div>
|
||||
${common}
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
<p style="margin:0px">Please, follow these steps:</p>
|
||||
<ul>
|
||||
<li>Reach out the person responsible for this scenario for support.</li>
|
||||
<li>As soon as it's possible, consider destroy this provision since it's taking valuable cloud resources which might imply relevant cost.</li>
|
||||
</ul>
|
||||
</div>
|
||||
${common}
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@@ -213,26 +206,24 @@ function getHtmlDestroyProvision(provision, scenario) {
|
||||
<p style="margin:0px">Scenario '${scenario.title}' successfully destroyed!</p>
|
||||
</div>
|
||||
${common}
|
||||
<div style="color:#404040;font-size:16px;margin:30px 0px">
|
||||
<p style="margin:0px">Check it out at <a href="https://qmicloud.qliktech.com">https://qmicloud.qliktech.com</a></p>
|
||||
</div>
|
||||
${FOOTER}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
|
||||
// async..await is not allowed in global scope, must use a wrapper
|
||||
async function send( provision, scenario ) {
|
||||
async function sendProvisionSuccess( provision, scenario ) {
|
||||
const htmlText = getHtmlNewProvision(provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision finished successfully', htmlText);
|
||||
}
|
||||
|
||||
async function sendError(provision, scenario ) {
|
||||
async function sendProvisionError(provision, scenario ) {
|
||||
const htmlText = getHtmlErrorProvision(provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision with failures', htmlText);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision with errors', htmlText);
|
||||
}
|
||||
|
||||
async function sendDestroyed(provision, scenario ) {
|
||||
async function sendDestroyedSuccess(provision, scenario ) {
|
||||
|
||||
const htmlText = getHtmlDestroyProvision(provision, scenario);
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - Provision destroyed successfully', htmlText);
|
||||
@@ -257,11 +248,12 @@ async function sendVMsStopped( provision, scenario ) {
|
||||
await _doSend(provision.user.upn, 'QMI Cloud - VMs stopped automatically', htmlText);
|
||||
}
|
||||
|
||||
module.exports.send = send;
|
||||
module.exports.sendError = sendError;
|
||||
module.exports.sendDestroyed = sendDestroyed;
|
||||
module.exports.sendProvisionSuccess = sendProvisionSuccess;
|
||||
module.exports.sendProvisionError = sendProvisionError;
|
||||
module.exports.sendDestroyedSuccess = sendDestroyedSuccess;
|
||||
module.exports.sendWillStopIn24 = sendWillStopIn24;
|
||||
module.exports.sendVMsStopped = sendVMsStopped;
|
||||
module.exports.sendWillDestroyIn24 = sendWillDestroyIn24;
|
||||
module.exports._doSend = _doSend;
|
||||
|
||||
|
||||
|
||||
7
qmi-cloud-common/test-sendemail.js
Normal file
@@ -0,0 +1,7 @@
|
||||
var sendEmail = require("./send-email");
|
||||
|
||||
function test(){
|
||||
|
||||
sendEmail._doSend("AOR@qlik.com", "Test subject", "Hi world");
|
||||
}
|
||||
test();
|
||||
85
qmi-cloud-common/utils.js
Normal file
@@ -0,0 +1,85 @@
|
||||
const db = require("./mongo");
|
||||
const sendEmail = require("./send-email");
|
||||
|
||||
async function afterStopVms( provision, auto ) {
|
||||
let timeRunning = db.utils.getNewTimeRunning(provision);
|
||||
const dateNow = new Date();
|
||||
let patch = {
|
||||
"statusVms": "Stopped",
|
||||
"timeRunning": timeRunning,
|
||||
"stoppedFrom": dateNow,
|
||||
"pendingNextAction": undefined
|
||||
};
|
||||
|
||||
if ( auto && provision._scenarioDoc ) { //From CLI (auto stop)
|
||||
let msg = "";
|
||||
// Actual onschedule reset
|
||||
if ( provision.schedule && !provision.schedule.is24x7 ) {
|
||||
patch["startDateOnSchedule"] = dateNow;
|
||||
patch["endDateOnSchedule"] = dateNow;
|
||||
msg = "Schedule time has been reset.";
|
||||
} else {
|
||||
msg = "24x7 vms auto-stopped due to limitted running time reached.";
|
||||
}
|
||||
|
||||
msg += `New totalTimeRunning: ${timeRunning} mins`;
|
||||
|
||||
await db.provision.update(provision._id.toString(), patch);
|
||||
await sendEmail.sendVMsStopped(provision, provision._scenarioDoc);
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'vms.stop-auto', message: msg });
|
||||
|
||||
} else { //On Demand stop
|
||||
let msg = "";
|
||||
if ( provision.schedule && !provision.schedule.is24x7 ) {
|
||||
patch["endDateOnSchedule"] = dateNow;
|
||||
|
||||
//This is temporary, only to make sure there is some initial value soon
|
||||
if ( !provision["startDateOnSchedule"] ) {
|
||||
patch["startDateOnSchedule"] = dateNow;
|
||||
msg = "startDateOS: " + dateNow.toISOString();
|
||||
} else {
|
||||
msg = "startDateOS: " + new Date(provision.startDateOnSchedule).toISOString();
|
||||
}
|
||||
msg += (" - endDateOS: " + dateNow.toISOString());
|
||||
|
||||
}
|
||||
|
||||
msg += ` - New totalTimeRunning: ${timeRunning} mins`;
|
||||
|
||||
await db.provision.update(provision._id.toString(), patch);
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'vms.stop-ondemand', message: msg });
|
||||
}
|
||||
}
|
||||
|
||||
async function afterStartVms( provision ) {
|
||||
const dateNow = new Date();
|
||||
let countExtend = db.utils.getNewCountExtend(provision);
|
||||
var patch = {
|
||||
"statusVms": "Running",
|
||||
"runningFrom": dateNow,
|
||||
"countExtend": countExtend,
|
||||
"pendingNextAction": undefined
|
||||
};
|
||||
|
||||
// Actual onschedule reset
|
||||
let msg = "";
|
||||
if ( provision.schedule && !provision.schedule.is24x7 ) {
|
||||
msg = "Schedule time has been reset.";
|
||||
patch["startDateOnSchedule"] = dateNow;
|
||||
patch["endDateOnSchedule"] = dateNow;
|
||||
} else {
|
||||
msg = `24x7, New count extend: ${countExtend}`;
|
||||
}
|
||||
|
||||
msg += `TotalTimeRunning so far: ${provision.timeRunning} mins`;
|
||||
|
||||
await db.provision.update(provision._id.toString(), patch);
|
||||
console.log("AzureCLI# All VMs RUNNING for resource group: "+rgName);
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'vms.start-ondemand', message: msg });
|
||||
|
||||
}
|
||||
|
||||
module.exports.afterStopVms = afterStopVms;
|
||||
module.exports.afterStartVms = afterStartVms;
|
||||
1286
qmi-cloud-common/yarn.lock
Normal file
@@ -1,7 +1,7 @@
|
||||
# Stage 1: NOTE: context is actually ../
|
||||
FROM node:13.8-alpine AS sources
|
||||
FROM node:15.12.0-alpine AS sources
|
||||
|
||||
RUN apk --no-cache add yarn
|
||||
RUN apk --no-cache add yarn git
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -11,7 +11,7 @@ ADD ./qmi-cloud-common ../qmi-cloud-common
|
||||
RUN yarn install --production
|
||||
|
||||
# Stage 2:
|
||||
FROM node:13.8-alpine AS production
|
||||
FROM node:15.12.0-alpine AS production
|
||||
WORKDIR /app
|
||||
COPY --from=sources /app ./
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ const PROJECT_PATH = process.env.PROJECT_PATH;
|
||||
const tf = require("./docker/tf");
|
||||
const azure = require("./docker/azure");
|
||||
const sendEmail = require("qmi-cloud-common/send-email");
|
||||
const barracuda = require("qmi-cloud-common/barracuda");
|
||||
|
||||
module.exports = async function(job) {
|
||||
|
||||
@@ -21,6 +22,8 @@ module.exports = async function(job) {
|
||||
|
||||
var idProv = prov._id.toString();
|
||||
|
||||
db.event.add({ user: prov.user._id, provision: prov._id, type: 'provision.init' });
|
||||
|
||||
// TERRAFORM INIT
|
||||
return tf.init(prov)
|
||||
.then(async function(res) {
|
||||
@@ -37,7 +40,19 @@ module.exports = async function(job) {
|
||||
console.log(`ProcessorApply# Error at Terraform PLAN for provision (${idProv}) `);
|
||||
return Promise.reject({"success": false, "error": "Error at Terraform Plan", provStatus: "error_plan"});
|
||||
} else {
|
||||
return await db.provision.update(prov._id,{"status": "provisioning", "statusVms": "Running", "runningFrom": new Date(), "runningTime": 0, "countExtend": 0});
|
||||
const dateNow = new Date();
|
||||
let patch = {
|
||||
"status": "provisioning",
|
||||
"statusVms": prov.vmImage? "Running" : "N/A",
|
||||
"runningFrom": dateNow,
|
||||
"runningTime": 0,
|
||||
"countExtend": 0
|
||||
};
|
||||
if ( prov.schedule && !prov.schedule.is24x7 ) {
|
||||
patch["startDateOnSchedule"] = dateNow;
|
||||
patch["endDateOnSchedule"] = dateNow;
|
||||
}
|
||||
return await db.provision.update(prov._id, patch);
|
||||
}
|
||||
} ).then( function(prov) {
|
||||
// TERRAFORM APPLY
|
||||
@@ -45,13 +60,29 @@ module.exports = async function(job) {
|
||||
} ).then( async function(res) {
|
||||
if ( res.statusCode === 1 ) {
|
||||
console.log(`ProcessorApply# Error at Terraform APPLY for provision (${idProv})`);
|
||||
} else if ( res.statusCode === 137 ){
|
||||
console.log(`ProcessorApply# Apply container must have been killed!`);
|
||||
return Promise.reject({"success": false, "error": "Apply container must have been killed", provStatus: "aborted"});
|
||||
}
|
||||
var status = ( res.output.indexOf("Error:") !== -1 )? "error" : "provisioned";
|
||||
return await db.provision.update(prov._id, {"status": status});
|
||||
} ).then( async function(prov) {
|
||||
return tf.outputs(prov).then( async function(outputs){
|
||||
if ( outputs.barracudaAzureFqdn ) {
|
||||
let fqdn = outputs.barracudaAzureFqdn;
|
||||
delete outputs['barracudaAzureFqdn'];
|
||||
return await db.provision.update(prov._id, {"barracudaAzureFqdn": fqdn, "outputs": outputs});
|
||||
} else {
|
||||
return await db.provision.update(prov._id, {"outputs": outputs});
|
||||
}
|
||||
});
|
||||
|
||||
} ).then( async function(prov) {
|
||||
if ( prov.isExternalAccess && prov.barracudaAzureFqdn ) {
|
||||
console.log(`ProcessorApply# Calling Barracuda service to create App and DNS CName for provision (${prov._id})`);
|
||||
barracuda.createApp(prov);
|
||||
}
|
||||
return prov;
|
||||
} ).then( async function(prov) {
|
||||
// Application Gateway assign policy
|
||||
return azure.appgateway(prov, job.data._scenario);
|
||||
@@ -60,15 +91,22 @@ module.exports = async function(job) {
|
||||
return azure.createimage(prov, job.data._scenario);
|
||||
} ).then( function(prov) {
|
||||
if (prov.status === "provisioned") {
|
||||
sendEmail.send(prov, job.data._scenario);
|
||||
sendEmail.sendProvisionSuccess(prov, job.data._scenario);
|
||||
} else {
|
||||
sendEmail.sendError(prov, job.data._scenario);
|
||||
sendEmail.sendProvisionError(prov, job.data._scenario);
|
||||
}
|
||||
db.event.add({ user: prov.user._id, provision: prov._id, type: 'provision.finished' });
|
||||
return Promise.resolve({"success": true, provMongo: prov});
|
||||
} ).catch( function(err) {
|
||||
console.log("ProcessorApply# Provision: error", err);
|
||||
db.provision.update(prov._id, {"status": err.provStatus? err.provStatus : 'error'});
|
||||
sendEmail.sendError(prov, job.data._scenario);
|
||||
|
||||
var errormsg = err.provStatus? err.provStatus : 'error'
|
||||
db.provision.update(prov._id, {"status": errormsg});
|
||||
db.event.add({ user: prov.user._id, provision: prov._id, type: 'provision.'+errormsg });
|
||||
|
||||
if ( errormsg !== "aborted") {
|
||||
sendEmail.sendProvisionError(prov, job.data._scenario);
|
||||
}
|
||||
return Promise.reject({"success": false, "error": err});
|
||||
} );
|
||||
}
|
||||
@@ -3,9 +3,10 @@ const docker = new Docker({
|
||||
'socketPath': '/home/docker.sock'
|
||||
});
|
||||
const fs = require('fs');
|
||||
const config = require('qmi-cloud-common/config');
|
||||
const GIT_SCENARIOS = process.env.GIT_SCENARIOS;
|
||||
const GIT_TAG = process.env.GIT_TAG || "master";
|
||||
const DOCKERIMAGE = process.env.DOCKERIMAGE_TERRAFORM || "qlikgear/terraform:0.12.18";
|
||||
const DOCKERIMAGE = process.env.DOCKERIMAGE_TERRAFORM || "qlikgear/terraform:1.0.1";
|
||||
const SSHPATH = process.env.SSHPATH;
|
||||
|
||||
function hook_stdout(callback) {
|
||||
@@ -25,7 +26,7 @@ function hook_stdout(callback) {
|
||||
|
||||
function _buildVarsExec( exec, provision, scenario ) {
|
||||
|
||||
let prefix = scenario.name.toUpperCase();
|
||||
let prefix = provision.scenario.toUpperCase();
|
||||
|
||||
prefix = prefix.replace(/AZQMI/g, 'QMI');
|
||||
exec.push('-var');
|
||||
@@ -36,7 +37,7 @@ function _buildVarsExec( exec, provision, scenario ) {
|
||||
exec.push(`subscription_id=${provision.deployOpts.subsId}`);
|
||||
}
|
||||
//Deprecated
|
||||
else if ( scenario.subscription && scenario.subscription.subsId ) {
|
||||
else if ( scenario && scenario.subscription && scenario.subscription.subsId ) {
|
||||
exec.push('-var');
|
||||
exec.push(`subscription_id=${scenario.subscription.subsId}`);
|
||||
}
|
||||
@@ -60,7 +61,7 @@ function _buildVarsExec( exec, provision, scenario ) {
|
||||
|
||||
}
|
||||
//Deprecated
|
||||
else if ( scenario.subscription && scenario.subscription.vnetExists ) {
|
||||
else if ( scenario && scenario.subscription && scenario.subscription.vnetExists ) {
|
||||
exec.push('-var');
|
||||
exec.push(`subnet_id=${scenario.subscription.subnetId}`);
|
||||
|
||||
@@ -75,6 +76,11 @@ function _buildVarsExec( exec, provision, scenario ) {
|
||||
exec.push('-var');
|
||||
exec.push(`user_id=${provision.user.displayName}`);
|
||||
|
||||
if ( provision.scenario.indexOf('azqmi-qdi') !== -1 && provision.version && provision.version >= config.PROVISION_VERSION ) {
|
||||
exec.push('-var');
|
||||
exec.push(`user_email=${provision.user.upn}`);
|
||||
}
|
||||
|
||||
if (!provision.vmImage) {
|
||||
//Old way
|
||||
if ( provision.vmType ) {
|
||||
@@ -89,17 +95,20 @@ function _buildVarsExec( exec, provision, scenario ) {
|
||||
} else if ( provision.vmImage ) {
|
||||
//New way
|
||||
for ( let key in provision.vmImage ) {
|
||||
|
||||
if ( !provision.vmImage[key].disabled ) {
|
||||
|
||||
if ( provision.vmImage[key].nodeCount ) {
|
||||
exec.push('-var');
|
||||
exec.push(`agent_count_${key}=${provision[key].nodeCount}`);
|
||||
}
|
||||
|
||||
if ( provision.vmImage[key].vmType ) {
|
||||
|
||||
if ( !provision.vmImage[key].disabled ) {
|
||||
exec.push('-var');
|
||||
exec.push(`vm_type_${key}=${provision.vmImage[key].vmType}`);
|
||||
}
|
||||
} else {
|
||||
exec.push('-var');
|
||||
exec.push(`vm_type_${key}=ENABLED`);
|
||||
}
|
||||
|
||||
if ( provision.vmImage[key].diskSizeGb ) {
|
||||
@@ -107,10 +116,16 @@ function _buildVarsExec( exec, provision, scenario ) {
|
||||
exec.push(`disk_size_gb_${key}=${provision.vmImage[key].diskSizeGb}`);
|
||||
}
|
||||
|
||||
if ( provision.vmImage[key].version ) {
|
||||
if ( provision.vmImage[key].version && provision.vmImage[key].version.image) {
|
||||
exec.push('-var');
|
||||
exec.push(`image_reference_${key}=${provision.vmImage[key].version.image}`);
|
||||
}
|
||||
|
||||
if ( provision.vmImage[key].version && provision.vmImage[key].version.init_password) {
|
||||
exec.push('-var');
|
||||
exec.push(`image_reference_${key}_init_password=${provision.vmImage[key].version.init_password}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,9 +160,14 @@ const init = function( provision ) {
|
||||
const name = `qmi-tf-init-${provision._id}`;
|
||||
console.log(`Terraform# Init: will spin up container: ${name}`);
|
||||
var processStream = fs.createWriteStream(provision.logFile, {flags:'a'});
|
||||
let exec = ['terraform', 'init', '-no-color', `-from-module=${GIT_SCENARIOS}//${provision.scenario}?ref=${GIT_TAG}`];
|
||||
let gitBranch = GIT_TAG;
|
||||
if ( provision._scenarioDoc && provision._scenarioDoc.gitBranch && provision._scenarioDoc.gitBranch.trim() !== "") {
|
||||
gitBranch = provision._scenarioDoc.gitBranch;
|
||||
}
|
||||
let exec = ['terraform', 'init', '-no-color', `-from-module=${GIT_SCENARIOS}//${provision.scenario}?ref=${gitBranch}`];
|
||||
console.log('Terraform# Init: exec: '+exec.join(" "));
|
||||
var terraformImage = provision.terraformImage? provision.terraformImage : DOCKERIMAGE;
|
||||
console.log('Terraform# Init: version to use is : '+terraformImage);
|
||||
return docker.run(terraformImage, exec, processStream, {
|
||||
//"Env": ["VAR_ENV=whatever"],
|
||||
"name": name,
|
||||
@@ -180,6 +200,7 @@ const plan = function( provision, scenario ) {
|
||||
exec = _buildVarsExec(exec, provision, scenario);
|
||||
console.log('Terraform# Plan: exec: '+exec.join(" "));
|
||||
var terraformImage = provision.terraformImage? provision.terraformImage : DOCKERIMAGE;
|
||||
console.log('Terraform# Plan: version to use is : '+terraformImage);
|
||||
return docker.run(terraformImage, exec, processStream, {
|
||||
//"Env": ["VAR_ENV=whatever"],
|
||||
"name": name,
|
||||
@@ -213,6 +234,7 @@ const apply = function( provision ) {
|
||||
var exec = ['terraform', 'apply', 'tfplan', '-no-color'];
|
||||
console.log('Terraform# Apply: exec: '+exec.join(" "));
|
||||
var terraformImage = provision.terraformImage? provision.terraformImage : DOCKERIMAGE;
|
||||
console.log('Terraform# Apply: version to use is : '+terraformImage);
|
||||
return docker.run(terraformImage, exec, processStream, {
|
||||
//"Env": ["VAR_ENV=whatever"],
|
||||
"name": name,
|
||||
@@ -228,7 +250,7 @@ const apply = function( provision ) {
|
||||
let container = data[1];
|
||||
console.log(`Terraform# Apply: ${name} (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
||||
return container.remove().then(function(){
|
||||
console.log(`Terraform# Apply: ${name} removed!`);
|
||||
console.log(`Terraform# Apply: Container '${name}' removed!`);
|
||||
return data[0].StatusCode;
|
||||
});
|
||||
}).then(function(statusCode) {
|
||||
@@ -241,11 +263,12 @@ const destroy = function(destroyMongo, provision, scenario) {
|
||||
const name = `qmi-tf-destroy-${destroyMongo._id}`;
|
||||
console.log(`Terraform# Destroy: will spin up container: ${name}`);
|
||||
var processStream = fs.createWriteStream(destroyMongo.logFile, {flags:'a'});
|
||||
var exec = ['Terraform# terraform', 'destroy', '-auto-approve', '-no-color'];
|
||||
var exec = ['terraform', 'destroy', '-auto-approve', '-no-color'];
|
||||
exec = _buildVarsExec(exec, provision, scenario);
|
||||
console.log('Terraform# Destroy: exec: '+exec.join(" "));
|
||||
|
||||
var terraformImage = provision.terraformImage? provision.terraformImage : DOCKERIMAGE;
|
||||
console.log('Terraform# Destroy: version to use is : '+terraformImage);
|
||||
|
||||
return docker.run(terraformImage, exec, processStream, {
|
||||
//"Env": ["VAR_ENV=whatever"],
|
||||
@@ -261,7 +284,7 @@ const destroy = function(destroyMongo, provision, scenario) {
|
||||
var container = data[1];
|
||||
console.log(`Terraform# Destroy: '${name}' (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
||||
return container.remove().then(function(){
|
||||
console.log(`Terraform# Destroy: '${name}' removed!`);
|
||||
console.log(`Terraform# Destroy: Container '${name}' removed!`);
|
||||
return data[0].StatusCode;
|
||||
});
|
||||
}).then(async function(statusCode) {
|
||||
@@ -301,8 +324,8 @@ const outputs = function(provision) {
|
||||
console.log(`Terraform# Output: '${name}' (${container.id}) has finished with code: ${data[0].StatusCode}`);
|
||||
return container.remove();
|
||||
}).then(async function(data) {
|
||||
console.log(`Terraform# Output: '${name}' removed!`);
|
||||
console.log("Terraform# Output: tfout: " + tfout);
|
||||
console.log(`Terraform# Output: Container '${name}' removed!`);
|
||||
//console.log("Terraform# Output: tfout: " + tfout);
|
||||
var out = JSON.parse(tfout);
|
||||
var o = {};
|
||||
for (var key in out) {
|
||||
@@ -312,8 +335,48 @@ const outputs = function(provision) {
|
||||
});
|
||||
};
|
||||
|
||||
const stop = function(provision) {
|
||||
|
||||
if ( provision.status !== "provisioning" ) {
|
||||
console.log(`Terraform# Stop: provision (${provision._id}) is not provisioning`);
|
||||
return {"message": `Won't stop container: provision (${provision._id}) is not provisioning`};
|
||||
}
|
||||
|
||||
const name = `qmi-tf-apply-${provision._id}`;
|
||||
|
||||
console.log(`Terraform# Stop: will try to stop container: ${name}`);
|
||||
|
||||
return docker.listContainers().then(function(containers) {
|
||||
|
||||
var containerID;
|
||||
|
||||
for (let i=0;i<containers.length;i++) {
|
||||
if ( containers[i].Names && containers[i].Names.length ) {
|
||||
//console.log(`Terraform# Stop: debug container Names: ${containers[i].Names[0]}`);
|
||||
if ( containers[i].Names[0] === ("/"+name) ) {
|
||||
console.log(`Terraform# Stop: container found: ${name}`);
|
||||
containerID = containers[i].Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( containerID ) {
|
||||
console.log(`Terraform# Stop: stopping container: ${name} with ID ${containerID}`);
|
||||
return docker.getContainer(containerID).kill().then(function(){
|
||||
console.log(`Terraform# Stop: container stopped!!: ${name}`);
|
||||
return {"message": `container ${name} stopped`}
|
||||
});
|
||||
} else {
|
||||
console.log(`Terraform# Stop: container ${name} not found!`);
|
||||
return {"message": `container ${name} not found`};
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
module.exports.init = init;
|
||||
module.exports.plan = plan;
|
||||
module.exports.apply = apply;
|
||||
module.exports.destroy = destroy;
|
||||
module.exports.outputs = outputs;
|
||||
module.exports.stop = stop;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { queues, TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE } from 'qmi-cloud-common/queues';
|
||||
import { queues, TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE, STOP_CONTAINER_QUEUE } from 'qmi-cloud-common/queues';
|
||||
|
||||
var path = require("path");
|
||||
|
||||
@@ -6,6 +6,7 @@ var path = require("path");
|
||||
queues[TF_APPLY_QUEUE].process("tf_apply_job", 10, path.resolve(__dirname, 'processor-apply.js'));
|
||||
queues[TF_APPLY_QSEOK_QUEUE].process("tf_apply_qseok_job", 10, path.resolve(__dirname, 'processor-apply-qseok.js'));
|
||||
queues[TF_DESTROY_QUEUE].process("tf_destroy_job", 10, path.resolve(__dirname, 'processor-destroy.js'));
|
||||
queues[STOP_CONTAINER_QUEUE].process("tf_abort_apply_job", 10, path.resolve(__dirname, 'processor-stop-container.js'));
|
||||
|
||||
|
||||
console.log(`Worker queues started!`);
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qmi-cloud-worker",
|
||||
"version": "1.1.6",
|
||||
"version": "1.3.0",
|
||||
"scripts": {
|
||||
"start": "node -r esm index.js",
|
||||
"start:dev": "nodemon -r esm index.js",
|
||||
@@ -11,6 +11,7 @@
|
||||
"qmi-cloud-common": "../qmi-cloud-common",
|
||||
"dockerode": "^3.0.2",
|
||||
"esm": "^3.2.25",
|
||||
"nodemon": "^1.19.1"
|
||||
"nodemon": "^1.19.1",
|
||||
"axios": "^0.21.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ const tf = require('./docker/tf');
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const path = require('path');
|
||||
const sendEmail = require("qmi-cloud-common/send-email");
|
||||
const barracuda = require("qmi-cloud-common/barracuda");
|
||||
|
||||
module.exports = async function(job){
|
||||
|
||||
@@ -18,6 +19,16 @@ module.exports = async function(job){
|
||||
|
||||
var provMongo = await db.provision.getById(job.data.provId);
|
||||
|
||||
// Deleting Barracuda App if existed
|
||||
if ( provMongo.barracudaAppId ) {
|
||||
console.log(`ProcessorDestroy# Deleting Barracuda App...` );
|
||||
barracuda.deleteApp(provMongo);
|
||||
} else {
|
||||
console.log(`ProcessorDestroy# There is no barracuda to be deleted` );
|
||||
}
|
||||
|
||||
db.event.add({ user: provMongo.user._id, provision: provMongo._id, type: 'provision.destroy-init' });
|
||||
|
||||
return tf.destroy(destroyMongo, provMongo, job.data._scenario)
|
||||
.then(async function(res) {
|
||||
let update, update2;
|
||||
@@ -28,14 +39,16 @@ module.exports = async function(job){
|
||||
update = await db.destroy.update(destroyMongo._id, {"status": "destroyed"});
|
||||
let timeRunning = db.utils.getNewTimeRunning(provMongo);
|
||||
update2 = await db.provision.update(provMongo._id, {"isDestroyed": true, "timeRunning": timeRunning, "pendingNextAction": undefined, "actualDestroyDate": new Date()});
|
||||
sendEmail.sendDestroyed(update2, job.data._scenario);
|
||||
sendEmail.sendDestroyedSuccess(update2, job.data._scenario);
|
||||
}
|
||||
return { destroy: update, provision: update2 };
|
||||
}).then(async function(res) {
|
||||
|
||||
console.log(`ProcessorDestroy# Provision destroyed!` );
|
||||
db.event.add({ user: provMongo.user._id, provision: provMongo._id, type: 'provision.destroy-finished' });
|
||||
return Promise.resolve({"success": true, job: res});
|
||||
}).catch(function(err) {
|
||||
console.log("ProcessorDestroy# err", err);
|
||||
db.event.add({ user: provMongo.user._id, provision: provMongo._id, type: 'provision.destroy-error' });
|
||||
db.destroy.update(destroyMongo._id, {"status": "error", "isDestroyed": false});
|
||||
return Promise.reject({"success": false, "err": err});
|
||||
});
|
||||
|
||||
21
qmi-cloud-worker/processor-stop-container.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const tf = require("./docker/tf");
|
||||
|
||||
module.exports = async function(job) {
|
||||
|
||||
var prov = await db.provision.getById(job.data.provId);
|
||||
|
||||
if ( !prov ) {
|
||||
console.log(`ProcessorStopContainer# Error: Not found Provision object in Database (it should exist!), provisionId is: ${job.data.id}` );
|
||||
return Promise.reject({"success": false, "err": "Not found Provision object in Worker"});
|
||||
}
|
||||
|
||||
// TERRAFORM INIT
|
||||
return tf.stop(prov)
|
||||
.then( function(res) {
|
||||
return Promise.resolve( { "success": true, "output": res });
|
||||
} ).catch( function(err) {
|
||||
console.log("ProcessorStopContainer# Error:", err);
|
||||
return Promise.reject({"success": false, "error": err});
|
||||
} );
|
||||
}
|
||||
@@ -2,6 +2,70 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@azure/abort-controller@^1.0.0":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.4.tgz#fd3c4d46c8ed67aace42498c8e2270960250eafd"
|
||||
integrity sha512-lNUmDRVGpanCsiUN3NWxFTdwmdFI53xwhkTFfHDGTYk46ca7Ind3nanJc+U6Zj9Tv+9nTCWRBscWEW1DyKOpTw==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@azure/arm-compute@^15.0.0":
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/arm-compute/-/arm-compute-15.0.0.tgz#5d0d0c1db16adbb6db3d33ca376b120c68e6ae23"
|
||||
integrity sha512-ElV2MuYZ+B2+ygMx2iiM/u3C7WDRruZjkXzfk5p2O+UbWxjG6j/686OH3T+VSDqmzg+47AnIOTLu2v0u0H8FOw==
|
||||
dependencies:
|
||||
"@azure/ms-rest-azure-js" "^2.0.1"
|
||||
"@azure/ms-rest-js" "^2.0.4"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@azure/core-auth@^1.1.4":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.2.0.tgz#a5a181164e99f8446a3ccf9039345ddc9bb63bb9"
|
||||
integrity sha512-KUl+Nwn/Sm6Lw5d3U90m1jZfNSL087SPcqHLxwn2T6PupNKmcgsEbDjHB25gDvHO4h7pBsTlrdJAY7dz+Qk8GA==
|
||||
dependencies:
|
||||
"@azure/abort-controller" "^1.0.0"
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@azure/ms-rest-azure-env@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz#45809f89763a480924e21d3c620cd40866771625"
|
||||
integrity sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==
|
||||
|
||||
"@azure/ms-rest-azure-js@^2.0.1":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.1.0.tgz#8c90b31468aeca3146b06c7144b386fd4827f64c"
|
||||
integrity sha512-CjZjB8apvXl5h97Ck6SbeeCmU0sk56YPozPtTyGudPp1RGoHXNjFNtoOvwOG76EdpmMpxbK10DqcygI16Lu60Q==
|
||||
dependencies:
|
||||
"@azure/core-auth" "^1.1.4"
|
||||
"@azure/ms-rest-js" "^2.2.0"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@azure/ms-rest-js@^2.0.4", "@azure/ms-rest-js@^2.2.0":
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-2.2.3.tgz#8f0085f7768c69f17b3cdb20ce95728b452dc304"
|
||||
integrity sha512-sXOhOu/37Tr8428f32Jwuwga975Xw64pYg1UeUwOBMhkNgtn5vUuNRa3fhmem+I6f8EKoi6hOsYDFlaHeZ52jA==
|
||||
dependencies:
|
||||
"@azure/core-auth" "^1.1.4"
|
||||
"@types/node-fetch" "^2.3.7"
|
||||
"@types/tunnel" "0.0.1"
|
||||
abort-controller "^3.0.0"
|
||||
form-data "^2.5.0"
|
||||
node-fetch "^2.6.0"
|
||||
tough-cookie "^3.0.1"
|
||||
tslib "^1.10.0"
|
||||
tunnel "0.0.6"
|
||||
uuid "^3.3.2"
|
||||
xml2js "^0.4.19"
|
||||
|
||||
"@azure/ms-rest-nodeauth@^3.0.7":
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.7.tgz#73c399b0aef45c75104324b6617aa4e0a6c27875"
|
||||
integrity sha512-7Q1MyMB+eqUQy8JO+virSIzAjqR2UbKXE/YQZe+53gC8yakm8WOQ5OzGfPP+eyHqeRs6bQESyw2IC5feLWlT2A==
|
||||
dependencies:
|
||||
"@azure/ms-rest-azure-env" "^2.0.0"
|
||||
"@azure/ms-rest-js" "^2.0.4"
|
||||
adal-node "^0.1.28"
|
||||
|
||||
"@hapi/boom@^9.1.0":
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-9.1.0.tgz#0d9517657a56ff1e0b42d0aca9da1b37706fec56"
|
||||
@@ -14,16 +78,43 @@
|
||||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.0.4.tgz#e80ad4e8e8d2adc6c77d985f698447e8628b6010"
|
||||
integrity sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw==
|
||||
|
||||
"@types/node-fetch@^2.3.7":
|
||||
version "2.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb"
|
||||
integrity sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
form-data "^3.0.0"
|
||||
|
||||
"@types/node@*":
|
||||
version "14.14.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
|
||||
integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==
|
||||
|
||||
"@types/node@^8.0.47":
|
||||
version "8.10.61"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.61.tgz#d299136ce54bcaf1abaa4a487f9e4bedf6b0d393"
|
||||
integrity sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q==
|
||||
|
||||
"@types/tunnel@0.0.1":
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.1.tgz#0d72774768b73df26f25df9184273a42da72b19c"
|
||||
integrity sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
adal-node@^0.1.28:
|
||||
version "0.1.28"
|
||||
resolved "https://registry.yarnpkg.com/adal-node/-/adal-node-0.1.28.tgz#468c4bb3ebbd96b1270669f4b9cba4e0065ea485"
|
||||
@@ -118,13 +209,6 @@ async-each@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
|
||||
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
|
||||
|
||||
async@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4"
|
||||
integrity sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==
|
||||
dependencies:
|
||||
lodash "^4.14.0"
|
||||
|
||||
async@>=0.6.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
|
||||
@@ -150,13 +234,12 @@ aws4@^1.8.0:
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
|
||||
integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
|
||||
|
||||
azure-arm-compute@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/azure-arm-compute/-/azure-arm-compute-10.0.0.tgz#ce9ba2e4d6dd6b1174c34da2219700a8080f389b"
|
||||
integrity sha512-ehafNtcMKI6c00FT+xhPWPtzhYgHCZ675TUsaJ1FJ2bSpznih5EUrpir/4w519T4zbFBigszhnRK6eBkl78I9g==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
ms-rest "^2.5.0"
|
||||
ms-rest-azure "^2.5.5"
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -406,7 +489,7 @@ color-name@1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
@@ -609,11 +692,6 @@ duplexer3@^0.1.4:
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
|
||||
|
||||
duplexer@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||
integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
@@ -672,6 +750,11 @@ esm@^3.2.25:
|
||||
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
|
||||
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
|
||||
|
||||
event-target-shim@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||
|
||||
execa@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
|
||||
@@ -767,6 +850,11 @@ fill-range@^4.0.0:
|
||||
repeat-string "^1.6.1"
|
||||
to-regex-range "^2.1.0"
|
||||
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.3"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
|
||||
integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
|
||||
|
||||
for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
@@ -777,6 +865,24 @@ forever-agent@~0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@^2.5.0:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
|
||||
integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
@@ -985,6 +1091,11 @@ ioredis@^4.14.1:
|
||||
redis-parser "^3.0.0"
|
||||
standard-as-callback "^2.0.1"
|
||||
|
||||
ip-regex@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
||||
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
|
||||
|
||||
is-accessor-descriptor@^0.1.6:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
|
||||
@@ -1006,7 +1117,7 @@ is-binary-path@^1.0.0:
|
||||
dependencies:
|
||||
binary-extensions "^1.0.0"
|
||||
|
||||
is-buffer@^1.1.5, is-buffer@^1.1.6:
|
||||
is-buffer@^1.1.5:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
@@ -1301,7 +1412,7 @@ lodash.flatten@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lodash@^4.14.0, lodash@^4.17.15:
|
||||
lodash@^4.17.15:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
@@ -1406,7 +1517,7 @@ moment-timezone@^0.5.31:
|
||||
dependencies:
|
||||
moment ">= 2.9.0"
|
||||
|
||||
"moment@>= 2.9.0", moment@^2.21.0, moment@^2.22.2:
|
||||
"moment@>= 2.9.0":
|
||||
version "2.26.0"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
|
||||
integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
|
||||
@@ -1462,44 +1573,6 @@ mquery@3.2.2:
|
||||
safe-buffer "5.1.2"
|
||||
sliced "1.0.1"
|
||||
|
||||
ms-rest-azure@^2.5.5:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-2.6.0.tgz#2098efec529eecfa0c6e215b69143abcaba12140"
|
||||
integrity sha512-J6386a9krZ4VtU7CRt+Ypgo9RGf8+d3gjMBkH7zbkM4zzkhbbMOYiPRaZ+bHZcfihkKLlktTgA6rjshTjF329A==
|
||||
dependencies:
|
||||
adal-node "^0.1.28"
|
||||
async "2.6.0"
|
||||
moment "^2.22.2"
|
||||
ms-rest "^2.3.2"
|
||||
request "^2.88.0"
|
||||
uuid "^3.2.1"
|
||||
|
||||
ms-rest-azure@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms-rest-azure/-/ms-rest-azure-3.0.0.tgz#54d0341c2aeef7b9f17f2a46258788740b2f0ec5"
|
||||
integrity sha512-cttN01/TtMDB4v3rt/WQ/slgffB6jcUYxcPzcL0VNSB+WFPE1j4y5ICNHMuD1RaNNekCYMI4Pv51BDQ/BXNq7Q==
|
||||
dependencies:
|
||||
adal-node "^0.1.28"
|
||||
async "2.6.0"
|
||||
moment "^2.22.2"
|
||||
ms-rest "^2.3.2"
|
||||
request "^2.88.0"
|
||||
uuid "^3.2.1"
|
||||
|
||||
ms-rest@^2.3.2, ms-rest@^2.5.0:
|
||||
version "2.5.4"
|
||||
resolved "https://registry.yarnpkg.com/ms-rest/-/ms-rest-2.5.4.tgz#57b42299cf302e45d5e1a734220bf7d4a110167a"
|
||||
integrity sha512-VeqCbawxRM6nhw0RKNfj7TWL7SL8PB6MypqwgylXCi+u412uvYoyY/kSmO8n06wyd8nIcnTbYToCmSKFMI1mCg==
|
||||
dependencies:
|
||||
duplexer "^0.1.1"
|
||||
is-buffer "^1.1.6"
|
||||
is-stream "^1.1.0"
|
||||
moment "^2.21.0"
|
||||
request "^2.88.0"
|
||||
through "^2.3.8"
|
||||
tunnel "0.0.5"
|
||||
uuid "^3.2.1"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@@ -1532,6 +1605,11 @@ nanomatch@^1.2.9:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
node-fetch@^2.6.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
nodemailer@^6.4.2:
|
||||
version "6.4.8"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.8.tgz#aca52886e4e56f71f6b8a65f5ca6b767ca751fc7"
|
||||
@@ -1752,13 +1830,14 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qmi-cloud-common@../qmi-cloud-common:
|
||||
version "1.1.2"
|
||||
version "1.1.6"
|
||||
dependencies:
|
||||
"@azure/arm-compute" "^15.0.0"
|
||||
"@azure/ms-rest-nodeauth" "^3.0.7"
|
||||
"@hapi/boom" "^9.1.0"
|
||||
azure-arm-compute "^10.0.0"
|
||||
axios "^0.21.1"
|
||||
bull "^3.11.0"
|
||||
mongoose "^5.7.4"
|
||||
ms-rest-azure "^3.0.0"
|
||||
nodemailer "^6.4.2"
|
||||
|
||||
qs@~6.5.2:
|
||||
@@ -1867,7 +1946,7 @@ repeat-string@^1.6.1:
|
||||
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
||||
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
|
||||
|
||||
"request@>= 2.52.0", request@^2.88.0:
|
||||
"request@>= 2.52.0":
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
@@ -1945,6 +2024,11 @@ saslprep@^1.0.0:
|
||||
dependencies:
|
||||
sparse-bitfield "^3.0.3"
|
||||
|
||||
sax@>=0.6.0:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
semver-diff@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
|
||||
@@ -2226,11 +2310,6 @@ term-size@^1.2.0:
|
||||
dependencies:
|
||||
execa "^0.7.0"
|
||||
|
||||
through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||
|
||||
timed-out@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
|
||||
@@ -2268,6 +2347,15 @@ touch@^3.1.0:
|
||||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
tough-cookie@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
||||
integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==
|
||||
dependencies:
|
||||
ip-regex "^2.1.0"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
@@ -2276,6 +2364,16 @@ tough-cookie@~2.5.0:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tslib@^1.10.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
@@ -2283,10 +2381,10 @@ tunnel-agent@^0.6.0:
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tunnel@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.5.tgz#d1532254749ed36620fcd1010865495a1fa9d0ae"
|
||||
integrity sha512-gj5sdqherx4VZKMcBA4vewER7zdK25Td+z1npBqpbDys4eJrLx+SlYjJvq1bDXs2irkuJM5pf8ktaEQVipkrbA==
|
||||
tunnel@0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
@@ -2400,7 +2498,7 @@ util.promisify@^1.0.1:
|
||||
has-symbols "^1.0.1"
|
||||
object.getownpropertydescriptors "^2.1.0"
|
||||
|
||||
uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2, uuid@^3.4.0:
|
||||
uuid@^3.1.0, uuid@^3.3.2, uuid@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
@@ -2447,6 +2545,19 @@ xdg-basedir@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
|
||||
integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
|
||||
|
||||
xml2js@^0.4.19:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||
dependencies:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~11.0.0"
|
||||
|
||||
xmlbuilder@~11.0.0:
|
||||
version "11.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
|
||||
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
|
||||
|
||||
"xmldom@>= 0.1.x":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a"
|
||||
|
||||
@@ -6,6 +6,9 @@ const config = require('./config');
|
||||
const MongoStore = require('connect-mongo')(expressSession);
|
||||
const mongoose = require('mongoose');
|
||||
const db = require("qmi-cloud-common/mongo");
|
||||
const axios = require('axios');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Start QuickStart here
|
||||
|
||||
@@ -89,6 +92,19 @@ passport.use(new OIDCStrategy({
|
||||
//console.log("jwtClaims", jwtClaims);
|
||||
//console.log("params", params);
|
||||
console.log(`Passport# new login from: ${profile.upn} (${profile.displayName})` );
|
||||
|
||||
//Save user photo
|
||||
axios({
|
||||
method: 'get',
|
||||
url: 'https://graph.microsoft.com/v1.0/me/photo/$value',
|
||||
responseType: 'stream',
|
||||
headers: { 'Authorization' : 'Bearer '+accessToken }
|
||||
}).then(function (response) {
|
||||
response.data.pipe(fs.createWriteStream(path.resolve(__dirname, '..', 'photos', `${profile.oid}.jpg`)));
|
||||
}).catch(function(err){
|
||||
console.log('Passport# Warning: No picture found');
|
||||
});
|
||||
|
||||
// asynchronous verification, for effect...
|
||||
process.nextTick(function () {
|
||||
_findByOid(profile.oid, async function(err, user) {
|
||||
@@ -125,7 +141,9 @@ module.exports.init = function(app){
|
||||
autoRemove: 'interval',
|
||||
autoRemoveInterval: 10
|
||||
//clear_interval: config.mongoDBSessionMaxAge
|
||||
})
|
||||
}),
|
||||
resave: true,
|
||||
saveUninitialized: false
|
||||
}));
|
||||
} else {
|
||||
app.use(expressSession({ secret: 'keyboard cat', resave: true, saveUninitialized: false }));
|
||||
@@ -240,7 +258,8 @@ module.exports.ensureAuthenticatedAndAdmin = async function(req, res, next) {
|
||||
|
||||
module.exports.ensureAuthenticatedAndIsMe = async function (req, res, next) {
|
||||
if ( await isApiKeyAuthenticated(req) || req.isAuthenticated() ) {
|
||||
if ( req.user._id == req.params.userId || req.user.role === 'admin' || req.user.role === 'superadmin' ) {
|
||||
var userId = (req.params.userId === 'me')? req.user._id : req.params.userId;
|
||||
if ( req.user._id == userId || req.user.role === 'admin' || req.user.role === 'superadmin' ) {
|
||||
return next();
|
||||
} else {
|
||||
return res.status(401).send("Error: Unauthorized");
|
||||
|
||||
@@ -23,15 +23,18 @@ const passport = require('../passport');
|
||||
* description: Notifications
|
||||
*/
|
||||
router.post('/updates', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
|
||||
const now = new Date().toISOString();
|
||||
|
||||
const dateNow = new Date();
|
||||
const now = dateNow.toISOString();
|
||||
try {
|
||||
|
||||
let event = req.body;
|
||||
const event = req.body;
|
||||
let logEvent = event.logEvent || 'DivvyCloud';
|
||||
|
||||
|
||||
if ( event.cloudName === 'QMI Automation' ) {
|
||||
|
||||
console.log(`DivvyCloud (${now})# event received for subscription (${event.cloudName}) - provision (${event.provID}) -> new status (${event.instanceState})`);
|
||||
console.log(`${logEvent} (${now})# event received for subscription (${event.cloudName}) - provision (${event.provID}) -> new status (${event.instanceState})`);
|
||||
|
||||
if ( event.provID && event.provID !== 'None' ) {
|
||||
|
||||
@@ -41,50 +44,91 @@ router.post('/updates', passport.ensureAuthenticatedAndAdmin, async (req, res, n
|
||||
|
||||
let id = provision._id.toString();
|
||||
|
||||
console.log(`DivvyCloud (${now})# provision (${id}) - scenario is (${provision.scenario} - v${provision.scenarioVersion})`);
|
||||
console.log(`${logEvent} (${now})# provision (${id}) - scenario is (${provision.scenario} - v${provision.scenarioVersion})`);
|
||||
|
||||
if ( provision.status === 'provisioned' ) {
|
||||
if ( provision.status === 'provisioned' || provision.status === 'error' ) {
|
||||
|
||||
if ( event.instanceState === 'Stopped' ) {
|
||||
|
||||
if ( provision.statusVms === 'Stopped' ) {
|
||||
console.log(`DivvyCloud (${now})# provision (${id}) - VMs were already Stopped!`);
|
||||
console.log(`${logEvent} (${now})# provision (${id}) - VMs were already Stopped!`);
|
||||
} else {
|
||||
|
||||
let timeRunning = db.utils.getNewTimeRunning(provision);
|
||||
await db.provision.update(id, {"statusVms": "Stopped", "timeRunning": timeRunning, "stoppedFrom": new Date(), "pendingNextAction": undefined});
|
||||
console.log(`DivvyCloud (${now})# provision (${id}) - VMs changed to Stopped!`);
|
||||
let patch = {
|
||||
"statusVms": "Stopped",
|
||||
"timeRunning": timeRunning,
|
||||
"stoppedFrom": dateNow,
|
||||
"pendingNextAction": undefined
|
||||
};
|
||||
|
||||
let msg = "";
|
||||
|
||||
if ( provision.schedule && !provision.schedule.is24x7 ) {
|
||||
patch["endDateOnSchedule"] = dateNow;
|
||||
|
||||
//This is temporary, only to make sure there is value
|
||||
if ( !provision["startDateOnSchedule"] ) {
|
||||
patch["startDateOnSchedule"] = dateNow;
|
||||
msg = "startDateOS: " + dateNow.toISOString();
|
||||
} else {
|
||||
msg = "startDateOS: " + new Date(provision.startDateOnSchedule).toISOString();
|
||||
}
|
||||
msg += (" - endDateOS: " + dateNow.toISOString());
|
||||
}
|
||||
msg += ` - New totalTimeRunning: ${timeRunning} mins`;
|
||||
|
||||
await db.provision.update(id, patch);
|
||||
console.log(`${logEvent} (${now})# provision (${id}) - VMs changed to Stopped!`);
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'vms.stop-schedule', message: msg });
|
||||
}
|
||||
|
||||
} else if ( event.instanceState === 'Running' ) {
|
||||
|
||||
if ( provision.statusVms === 'Running' ) {
|
||||
console.log(`DivvyCloud (${now})# provision (${id}) - VMs were already Running!`);
|
||||
console.log(`${logEvent} (${now})# provision (${id}) - VMs were already Running!`);
|
||||
} else {
|
||||
await db.provision.update(id, {"statusVms": "Running", "runningFrom": new Date(), "pendingNextAction": undefined});
|
||||
console.log(`DivvyCloud (${now})# provision (${id}) - VMs changed to Running!`);
|
||||
let patch = {
|
||||
"statusVms": "Running",
|
||||
"runningFrom": dateNow,
|
||||
"pendingNextAction": undefined
|
||||
};
|
||||
|
||||
// This is temporary, only to make sure there are values soon
|
||||
if ( provision.schedule && !provision.schedule.is24x7 ) {
|
||||
if ( !provision["startDateOnSchedule"] ) {
|
||||
patch["startDateOnSchedule"] = dateNow;
|
||||
patch["endDateOnSchedule"] = dateNow;
|
||||
}
|
||||
}
|
||||
|
||||
await db.provision.update(id, patch);
|
||||
console.log(`${logEvent} (${now})# provision (${id}) - VMs changed to Running!`);
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'vms.start-schedule', message: `TimeRunning so far: ${provision.timeRunning} mins` });
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(`DivvyCloud (${now})# provision (${event.provID}) - Scenario not yet 'provisioned'`);
|
||||
console.log(`${logEvent} (${now})# provision (${event.provID}) - Scenario not yet 'provisioned'`);
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(`DivvyCloud (${now})# provision (${event.provID}) - Provision not found.`);
|
||||
console.log(`${logEvent} (${now})# provision (${event.provID}) - Provision not found.`);
|
||||
}
|
||||
|
||||
} else {
|
||||
console.log(`DivvyCloud (${now})# 'provID' attribute is missing.`);
|
||||
console.log(`${logEvent} (${now})# 'provID' attribute is missing.`);
|
||||
}
|
||||
|
||||
} else {
|
||||
//console.log(`DivvyCloud (${now}): event received for subscription (${event.cloudName}) --> won't be processed`);
|
||||
//console.log(`${logEvent} (${now}): event received for subscription (${event.cloudName}) --> won't be processed`);
|
||||
}
|
||||
|
||||
return res.json(req.body);
|
||||
|
||||
} catch (error) {
|
||||
console.log(`DivvyCloud (${now})# error!!!!`, error);
|
||||
console.log(`${logEvent} (${now})# error!!!!`, error);
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const passport = require('../passport');
|
||||
const sendEmail = require('qmi-cloud-common/send-email');
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,4 +35,27 @@ router.get('/', passport.ensureAuthenticatedAndAdmin, async (req, res, next) =>
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /notifications/testsendemail:
|
||||
* post:
|
||||
* description: Get all notifications
|
||||
* summary: Get all notifications
|
||||
* tags:
|
||||
* - admin
|
||||
* produces:
|
||||
* - application/json
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Notifications
|
||||
*/
|
||||
router.post('/testsendemail', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
|
||||
try {
|
||||
const result = await sendEmail._doSend(req.user.upn, "QMI - Test email", "Hi! This is a test email from QMI Cloud.");
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -338,7 +338,7 @@ router.post('/:id/updatetagsvms', passport.ensureAuthenticatedAndAdmin, async (r
|
||||
if (!provision) {
|
||||
return res.status(404).json({"msg": "Not found provision with id: "+req.params.id, "success": false});
|
||||
}
|
||||
var result = await azurecli.updateVmsTags(provision._id, tagsEdit);
|
||||
var result = await cli.updateVmsTags(provision._id, tagsEdit);
|
||||
return res.json({"msg": "Tags are being updated", "result": result, "success": true});
|
||||
|
||||
} catch (error) {
|
||||
|
||||
227
server/routes/api-stats.js
Normal file
@@ -0,0 +1,227 @@
|
||||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const moment = require('moment');
|
||||
const azurecli = require('qmi-cloud-common/azurecli');
|
||||
|
||||
const CACHED_PERIOD = 30; //minutes
|
||||
var cachedTime;
|
||||
var cachedTimeVms;
|
||||
var cachedStats;
|
||||
var cachedVms;
|
||||
/**
|
||||
* @swagger
|
||||
* /stats:
|
||||
* get:
|
||||
* description: Get overall stats
|
||||
* summary: Get overall stats
|
||||
* produces:
|
||||
* - application/json
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Stats
|
||||
* 404:
|
||||
* description: Not found
|
||||
*
|
||||
*/
|
||||
router.get('/', async (req, res, next) => {
|
||||
try {
|
||||
var now = new Date().getTime();
|
||||
var nowMinus5mins = now - CACHED_PERIOD*60*1000;
|
||||
|
||||
if ( (!req.query.disablecache || req.query.disablecache === 'no') && cachedStats && cachedTime && cachedTime > nowMinus5mins ) {
|
||||
console.log("APIStats# Stats: return cached value");
|
||||
cachedTime = now;
|
||||
return res.json(cachedStats);
|
||||
|
||||
} else {
|
||||
console.log("APIStats# Stats: new value");
|
||||
let filterActiveP = { "isDestroyed": false, "status": "provisioned" };
|
||||
let filterPRunning = { "isDestroyed": false, "status": "provisioned", "statusVms" : "Running" };
|
||||
let initCurrentMonth = moment().startOf('month');
|
||||
let initLastMonth = moment(initCurrentMonth).add(-1, 'months');
|
||||
let today = moment();
|
||||
let todayLastMonth = moment().add(-1, "months");
|
||||
let filterTotalPCurrentMonth = { "status": "provisioned", "created": {
|
||||
$gte: initCurrentMonth.toISOString(),
|
||||
$lt: today.toISOString()
|
||||
} };
|
||||
let filterTotalPLastMonth = { "status": "provisioned", "created": {
|
||||
$gte: initLastMonth.toISOString(),
|
||||
$lt: todayLastMonth.toISOString()
|
||||
} };
|
||||
|
||||
//Counts
|
||||
let totalActiveP = await db.provision.count(filterActiveP);
|
||||
let totalCPRunning = await db.provision.count(filterPRunning);
|
||||
|
||||
let totalPCurrentmonth = await db.provision.count(filterTotalPCurrentMonth);
|
||||
let totalPLastmonth = await db.provision.count(filterTotalPLastMonth);
|
||||
|
||||
let totalUsers = await db.user.count({});
|
||||
let totalAuthUsers = await db.user.count({
|
||||
"lastLogin": {$gte: moment().add(-12, "hours").toISOString()}
|
||||
});
|
||||
let totalScenarios = await db.scenario.count({"isDisabled":false, "isAdminOnly": false});
|
||||
|
||||
cachedStats = {
|
||||
provisions: {
|
||||
active: totalActiveP,
|
||||
running: totalCPRunning,
|
||||
totalCurrentMonthPeriod: totalPCurrentmonth,
|
||||
totalLastMonthPerdiod:totalPLastmonth
|
||||
},
|
||||
users: {
|
||||
total: totalUsers,
|
||||
activeNow: totalAuthUsers,
|
||||
active7days: await db.user.count({
|
||||
"lastLogin": {$gte: moment().add(-7, "days").toISOString()}
|
||||
}),
|
||||
active30days: await db.user.count({
|
||||
"lastLogin": {$gte: moment().add(-30, "days").toISOString()}
|
||||
})
|
||||
},
|
||||
scenarios: {
|
||||
total: totalScenarios
|
||||
}
|
||||
};
|
||||
cachedTime = now;
|
||||
|
||||
return res.json(cachedStats);
|
||||
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
function appendResult(list, output ){
|
||||
|
||||
list.forEach(v=>{
|
||||
if ( v.tags && v.tags["QMI_user"] ) {
|
||||
if (v.location) {
|
||||
if ( !output.locations[v.location] ) {
|
||||
output.locations[v.location] = 0;
|
||||
}
|
||||
output.locations[v.location] += 1;
|
||||
}
|
||||
|
||||
if (v.storageProfile && v.storageProfile.osDisk && v.storageProfile.osDisk.osType) {
|
||||
if ( !output.types[v.storageProfile.osDisk.osType] ) {
|
||||
output.types[v.storageProfile.osDisk.osType] = 0;
|
||||
}
|
||||
output.types[v.storageProfile.osDisk.osType] += 1;
|
||||
}
|
||||
|
||||
output.out.push(v);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /stats/vms:
|
||||
* get:
|
||||
* description: List azure vms
|
||||
* summary: List azure vms
|
||||
* produces:
|
||||
* - application/json
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Stats
|
||||
* 404:
|
||||
* description: Not found
|
||||
*
|
||||
*/
|
||||
router.get('/vms', async (req, res, next) => {
|
||||
|
||||
try {
|
||||
|
||||
var now = new Date().getTime();
|
||||
var nowMinus5mins = now - CACHED_PERIOD*60*1000;
|
||||
|
||||
if ( (!req.query.disablecache || req.query.disablecache === 'no') && cachedVms && cachedTimeVms && cachedTimeVms > nowMinus5mins ) {
|
||||
console.log("APIStats# VMs: return cached value");
|
||||
cachedTimeVms = now;
|
||||
return res.json(cachedVms);
|
||||
|
||||
} else {
|
||||
console.log("APIStats# VMs: new value");
|
||||
var output = {
|
||||
out : [],
|
||||
locations: {
|
||||
"eastus": 0,
|
||||
"westeurope": 0,
|
||||
"southeastasia": 0
|
||||
},
|
||||
types: {
|
||||
"Windows": 0,
|
||||
"Linux": 0
|
||||
}
|
||||
}
|
||||
|
||||
var result = await azurecli.getAllVms();
|
||||
output = appendResult(result, output);
|
||||
|
||||
if ( result.nextLink ) {
|
||||
console.log("There is a second page");
|
||||
|
||||
result = await azurecli.getAllVmsNext(result.nextLink);
|
||||
output = appendResult(result, output);
|
||||
|
||||
if ( result.nextLink ) {
|
||||
console.log("There is a third page");
|
||||
|
||||
result = await azurecli.getAllVmsNext(result.nextLink);
|
||||
output = appendResult(result, output);
|
||||
|
||||
if ( result.nextLink ) {
|
||||
console.log("There is a forth page");
|
||||
|
||||
result = await azurecli.getAllVmsNext(result.nextLink);
|
||||
output = appendResult(result, output);
|
||||
|
||||
if ( result.nextLink ) {
|
||||
console.log("There is a fifth page");
|
||||
|
||||
result = await azurecli.getAllVmsNext(result.nextLink);
|
||||
output = appendResult(result, output);
|
||||
|
||||
if ( result.nextLink ) {
|
||||
console.log("There is a sixth page");
|
||||
|
||||
result = await azurecli.getAllVmsNext(result.nextLink);
|
||||
output = appendResult(result, output);
|
||||
|
||||
if ( result.nextLink ) {
|
||||
console.log("There is a seventh page");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cachedTimeVms = now;
|
||||
cachedVms = {
|
||||
total: output.out.length,
|
||||
locations: output.locations,
|
||||
types: output.types
|
||||
};
|
||||
|
||||
return res.json(cachedVms);
|
||||
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -1,26 +1,14 @@
|
||||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const db = require('qmi-cloud-common/mongo');
|
||||
const config = require('qmi-cloud-common/config');
|
||||
const passport = require('../passport');
|
||||
const moment = require('moment');
|
||||
const fs = require('fs-extra');
|
||||
const azurecli = require('qmi-cloud-common/azurecli');
|
||||
const cli = require('qmi-cloud-common/cli');
|
||||
const barracuda = require('qmi-cloud-common/barracuda');
|
||||
|
||||
import { queues, TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE } from 'qmi-cloud-common/queues';
|
||||
|
||||
const RUNNING_PERIOD_ON_SCHEDULE = 4;
|
||||
|
||||
function timeRunningOnSchedule(p) {
|
||||
|
||||
let totalRunningTime = p.timeRunning*1000*60;
|
||||
if ( p.statusVms === 'Running' ) {
|
||||
let runningFromTime = p.runningFrom? new Date(p.runningFrom).getTime() : new Date(p.created).getTime();
|
||||
let now = new Date();
|
||||
totalRunningTime = totalRunningTime + Math.abs(now.getTime() - runningFromTime);
|
||||
}
|
||||
let duration = moment.duration(totalRunningTime);
|
||||
return Math.abs(duration.asHours());
|
||||
}
|
||||
import { queues, TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE, STOP_CONTAINER_QUEUE } from 'qmi-cloud-common/queues';
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
@@ -85,7 +73,8 @@ router.get('/me', passport.ensureAuthenticated, async (req, res, next) => {
|
||||
*/
|
||||
router.get('/:userId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
const result = await db.user.getById(req.params.userId);
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
const result = await db.user.getById(userId);
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -118,7 +107,8 @@ router.get('/:userId', passport.ensureAuthenticatedAndIsMe, async (req, res, nex
|
||||
router.put('/:userId', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const result = await db.user.update(req.params.userId, req.body);
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
const result = await db.user.update(userId, req.body);
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
@@ -176,23 +166,25 @@ router.put('/:userId', passport.ensureAuthenticatedAndAdmin, async (req, res, ne
|
||||
router.post('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
|
||||
req.body.user = req.params.userId;
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
req.body.user = userId;
|
||||
const scenarioSource = await db.scenario.getOne({name: req.body.scenario});
|
||||
|
||||
if (!scenarioSource) {
|
||||
return res.status(404).json({"msg": "Scenario not found "});
|
||||
}
|
||||
|
||||
const filterProvisions = {"user": req.params.userId, "isDestroyed": false, "isDeleted": false, "scenario": scenarioSource.name };
|
||||
const filterProvisions = {"user": userId, "isDestroyed": false, "isDeleted": false, "scenario": scenarioSource.name };
|
||||
const result = await db.provision.get(filterProvisions);
|
||||
|
||||
if ( scenarioSource.numSimultaneousProvisions && result.total >= scenarioSource.numSimultaneousProvisions ) {
|
||||
return res.status(400).json({"msg": "Number of simultaneous provisions reached for this scenario: " + scenarioSource.numSimultaneousProvisions});
|
||||
}
|
||||
|
||||
if (!req.body.vmImage || !req.body.vmImage.vm1 || !req.body.vmImage.vm1.vmType ) {
|
||||
return res.status(400).json({"msg": "Invalid vmImage"});
|
||||
}
|
||||
//if (!req.body.vmImage || !req.body.vmImage.vm1 || !req.body.vmImage.vm1.vmType ) {
|
||||
// return res.status(400).json({"msg": "Invalid vmImage"});
|
||||
//}
|
||||
|
||||
req.body.scenarioVersion = scenarioSource.version;
|
||||
|
||||
if ( req.body.scheduleData && req.body.scheduleData.is24x7 !== undefined ) {
|
||||
@@ -200,13 +192,20 @@ router.post('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (r
|
||||
req.body.schedule = schedule._id;
|
||||
}
|
||||
|
||||
req.body.terraformImage = config.DOCKERIMAGE_TERRAFORM;
|
||||
|
||||
if ( req.body.scenario.indexOf('azqmi-qdi') !== -1 ) {
|
||||
req.body.version = config.PROVISION_VERSION;
|
||||
}
|
||||
|
||||
|
||||
const provision = await db.provision.add(req.body);
|
||||
|
||||
|
||||
if ( provision.scenario === "azqmi-qseok" ){
|
||||
queues[TF_APPLY_QSEOK_QUEUE].add("tf_apply_qseok_job", {
|
||||
scenario: req.body.scenario,
|
||||
vmType: req.body.vmType,
|
||||
vmType: req.body.vmType || null,
|
||||
nodeCount: req.body.nodeCount,
|
||||
id: provision._id,
|
||||
user: req.user,
|
||||
@@ -230,6 +229,38 @@ router.post('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (r
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}:
|
||||
* get:
|
||||
* description: Get provision details
|
||||
* summary: Get provision details
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* - name: id
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* produces:
|
||||
* - application/json
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Provision
|
||||
*/
|
||||
router.get('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
let provision = await db.provision.getById(req.params.id);
|
||||
return res.json(provision);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}:
|
||||
@@ -264,18 +295,9 @@ router.put('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async
|
||||
try {
|
||||
|
||||
let schedule;
|
||||
var msg = "";
|
||||
if ( req.body.scheduleData ) {
|
||||
|
||||
// -- HERE onScheduleRenewed????
|
||||
var duration = timeRunningOnSchedule(provision); //hours
|
||||
var onScheduleRenewed = req.body.scheduleData.onScheduleRenewed? req.body.scheduleData.onScheduleRenewed : 1;
|
||||
if ( duration >= (24 * RUNNING_PERIOD_ON_SCHEDULE * onScheduleRenewed) ) {
|
||||
onScheduleRenewed = Math.ceil( duration/(24*RUNNING_PERIOD_ON_SCHEDULE) ) + 1;
|
||||
console.log("APIUser# onScheduleRenewed has been incremented!! -> ", onScheduleRenewed);
|
||||
}
|
||||
req.body.scheduleData["onScheduleRenewed"] = onScheduleRenewed;
|
||||
// --
|
||||
|
||||
if ( req.body.scheduleData._id ) {
|
||||
schedule = await db.schedule.update(req.body.scheduleData._id, req.body.scheduleData);
|
||||
} else {
|
||||
@@ -286,19 +308,27 @@ router.put('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async
|
||||
"StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false,
|
||||
"ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false
|
||||
}
|
||||
azurecli.updateVmsTags(provision._id, tagsEdit);
|
||||
cli.updateVmsTags(provision._id, tagsEdit);
|
||||
|
||||
}
|
||||
|
||||
let patch = {};
|
||||
if ( req.body.user ) {
|
||||
patch.user = req.body.user;
|
||||
msg += ` - new user: ${req.body.user}`;
|
||||
}
|
||||
if ( schedule ) {
|
||||
patch.schedule = schedule._id;
|
||||
msg += ` - new schedule: ${schedule._id}`;
|
||||
}
|
||||
|
||||
let result = {
|
||||
provision: await db.provision.update(provision._id, patch)
|
||||
provision: await db.provision.update(provision._id, patch),
|
||||
event: await db.event.updateMany({"provision": provision._id}, {"user": req.body.user})
|
||||
}
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'provision.update', message: msg });
|
||||
|
||||
return res.json(result);
|
||||
|
||||
} catch (error) {
|
||||
@@ -347,12 +377,205 @@ router.delete('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, as
|
||||
if (fs.existsSync(`/provisions/${provision.scenario}_${req.params.id}`)) {
|
||||
fs.moveSync(`/provisions/${provision.scenario}_${req.params.id}`, `/provisions/deleted/${provision.scenario}_${req.params.id}`, { overwrite: true })
|
||||
}
|
||||
|
||||
db.event.add({ user: provision.user._id, provision: provision._id, type: 'provision.delete-history' });
|
||||
|
||||
return res.json({"provision": delProv, "destroy": delProv.destroy});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}/barracuda:
|
||||
* get:
|
||||
* description: Barracuda - get details and provision status
|
||||
* summary: Barracuda - get details and provision status
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* - name: id
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Provision
|
||||
* 404:
|
||||
* description: Not found
|
||||
*
|
||||
*/
|
||||
router.get('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
|
||||
let provision = await db.provision.getById(req.params.id);
|
||||
if (!provision){
|
||||
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
|
||||
}
|
||||
|
||||
if ( !provision.barracudaAppId ) {
|
||||
console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAppId value!`);
|
||||
return res.status(404).json({"msg": "Not found Barracuda App for this provision"});
|
||||
}
|
||||
|
||||
var app = await barracuda.getApp(provision);
|
||||
return res.json(app);
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}/barracuda:
|
||||
* post:
|
||||
* description: Barracuda - give a provision external access
|
||||
* summary: Barracuda - give a provision external access
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* - name: id
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Provision
|
||||
* 404:
|
||||
* description: Not found
|
||||
*
|
||||
*/
|
||||
router.post('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
|
||||
let provision = await db.provision.getById(req.params.id);
|
||||
if (!provision){
|
||||
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
|
||||
}
|
||||
|
||||
if ( !provision.barracudaAzureFqdn ) {
|
||||
console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAzureFqdn value!`);
|
||||
return res.json(provision);
|
||||
}
|
||||
|
||||
if ( provision.barracudaAppId ) {
|
||||
console.log(`APIUser# Provision (${req.params.id}) already have a Barracuda App (${provision.barracudaAppId})!`);
|
||||
return res.json(provision);
|
||||
}
|
||||
|
||||
console.log(`APIUser# Calling Barracuda service to create App and DNS CName for provision (${provision._id})`);
|
||||
barracuda.createApp(provision);
|
||||
|
||||
return res.json(provision);
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}/barracuda:
|
||||
* delete:
|
||||
* description: Barracuda - delete a provision external access
|
||||
* summary: Barracuda - delete a provision external access
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* - name: id
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Provision
|
||||
* 404:
|
||||
* description: Not found
|
||||
*
|
||||
*/
|
||||
router.delete('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
|
||||
let provision = await db.provision.getById(req.params.id);
|
||||
if (!provision){
|
||||
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
|
||||
}
|
||||
|
||||
if ( !provision.barracudaAppId ) {
|
||||
console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAppId value!`);
|
||||
return res.json({});
|
||||
}
|
||||
|
||||
console.log(`APIUser# Calling Barracuda service to delete App and DNS CName for provision (${provision._id})`);
|
||||
barracuda.deleteApp(provision);
|
||||
|
||||
|
||||
return res.json(provision);
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}/abort:
|
||||
* post:
|
||||
* description: Abort provision
|
||||
* summary: Abort provision
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* - name: id
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Provision
|
||||
* 404:
|
||||
* description: Not found
|
||||
*
|
||||
*/
|
||||
router.post('/:userId/provisions/:id/abort', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
|
||||
let provision = await db.provision.getById(req.params.id);
|
||||
if (!provision){
|
||||
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
|
||||
}
|
||||
|
||||
queues[STOP_CONTAINER_QUEUE].add("tf_abort_apply_job", {
|
||||
provId: provision._id,
|
||||
user: req.user
|
||||
});
|
||||
|
||||
return res.json({"status": "aborting"});
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}/deallocatevms:
|
||||
@@ -394,10 +617,10 @@ router.post('/:userId/provisions/:id/deallocatevms', passport.ensureAuthenticate
|
||||
"StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false,
|
||||
"ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false
|
||||
}
|
||||
azurecli.updateVmsTags(provision._id, tagsEdit);
|
||||
cli.updateVmsTags(provision._id, tagsEdit);
|
||||
}
|
||||
|
||||
azurecli.deallocate(provision._id);
|
||||
cli.deallocate(provision._id);
|
||||
|
||||
return res.json({"statusVms": "Stopping"});
|
||||
|
||||
@@ -439,21 +662,10 @@ router.post('/:userId/provisions/:id/startvms', passport.ensureAuthenticatedAndI
|
||||
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
|
||||
}
|
||||
|
||||
azurecli.start(provision._id);
|
||||
|
||||
//Re-enable DivvyTags according to schedule
|
||||
if ( provision.schedule ) {
|
||||
|
||||
// -- onScheduleRenewed????
|
||||
var duration = timeRunningOnSchedule(provision); //hours
|
||||
var onScheduleRenewed = provision.schedule.onScheduleRenewed? provision.schedule.onScheduleRenewed : 1;
|
||||
if ( duration >= (24 * RUNNING_PERIOD_ON_SCHEDULE * onScheduleRenewed) ) {
|
||||
onScheduleRenewed = Math.ceil( duration/(24*RUNNING_PERIOD_ON_SCHEDULE) ) + 1;
|
||||
console.log("APIUser# onScheduleRenewed has been incremented!! -> ", onScheduleRenewed);
|
||||
}
|
||||
|
||||
//let schedule = await db.schedule.update(provision.schedule._id, {"isStartupTimeEnable": true, "onScheduleRenewed": onScheduleRenewed});
|
||||
let schedule = await db.schedule.update(provision.schedule._id, {"onScheduleRenewed": onScheduleRenewed});
|
||||
let schedule = await db.schedule.getById(provision.schedule._id);
|
||||
|
||||
console.log("APIUser# Re-enabling DivvyTags according to schedule");
|
||||
var tagsEdit = {
|
||||
@@ -461,8 +673,11 @@ router.post('/:userId/provisions/:id/startvms', passport.ensureAuthenticatedAndI
|
||||
"StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false,
|
||||
"ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false
|
||||
}
|
||||
azurecli.updateVmsTags(provision._id, tagsEdit);
|
||||
cli.updateVmsTags(provision._id, tagsEdit);
|
||||
}
|
||||
|
||||
cli.start(provision._id);
|
||||
|
||||
return res.json({"statusVms": "Starting"});
|
||||
|
||||
} catch (error) {
|
||||
@@ -547,13 +762,13 @@ router.post('/:userId/provisions/:id/extend', passport.ensureAuthenticatedAndIsM
|
||||
router.post('/:userId/provisions/:id/destroy', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
let provision = await db.provision.getById(req.params.id);
|
||||
if (!provision){
|
||||
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
|
||||
}
|
||||
|
||||
const destroyJob = await db.destroy.add({ "user": req.params.userId });
|
||||
const destroyJob = await db.destroy.add({ "user": userId });
|
||||
provision = await db.provision.update(req.params.id, {"destroy": destroyJob._id});
|
||||
const scenarioSource = await db.scenario.getOne({name: provision.scenario});
|
||||
|
||||
@@ -592,7 +807,8 @@ router.post('/:userId/provisions/:id/destroy', passport.ensureAuthenticatedAndIs
|
||||
router.get('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const filter = {"user": req.params.userId, "isDeleted": false};
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
const filter = {"user": userId, "isDeleted": false};
|
||||
const result = await db.provision.get(filter);
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
@@ -600,6 +816,109 @@ router.get('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (re
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/events:
|
||||
* get:
|
||||
* description: Get all Events for an User
|
||||
* summary: Get all Events for an User
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: JSON Array
|
||||
*/
|
||||
router.get('/:userId/events', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
const result = await db.event.get({"user": userId});
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/provisions/{id}/events:
|
||||
* get:
|
||||
* description: Get all Events for an User and Provision
|
||||
* summary: Get all Events for an User and Provision
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* - name: id
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: JSON Array
|
||||
*/
|
||||
router.get('/:userId/provisions/:id/events', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
const result = await db.event.get({"user": userId, "provision": req.params.id});
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{userId}/scenarios:
|
||||
* get:
|
||||
* description: Get all Provisions for an User
|
||||
* summary: Get all Provisions for an User
|
||||
* produces:
|
||||
* - application/json
|
||||
* parameters:
|
||||
* - name: userId
|
||||
* in: path
|
||||
* type: string
|
||||
* required: true
|
||||
* responses:
|
||||
* 200:
|
||||
* description: JSON Array
|
||||
*/
|
||||
router.get('/:userId/scenarios', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
try {
|
||||
let filter = {};
|
||||
if (req.user.role === "user") {
|
||||
filter.isAdminOnly = false;
|
||||
}
|
||||
filter.isDisabled = filter.isDisabled || false;
|
||||
var result = await db.scenario.get(filter);
|
||||
if (req.user.role === "user") {
|
||||
result.results = result.results.filter( scenario => {
|
||||
let noAllowedUsers = !scenario.allowedUsers || scenario.allowedUsers.length === 0;
|
||||
if ( noAllowedUsers ) {
|
||||
return true;
|
||||
} else {
|
||||
let allowedUserIds = scenario.allowedUsers.map( u=> u._id.toString());
|
||||
return allowedUserIds.indexOf(req.user._id.toString()) !== -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
return res.json(result);
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
@@ -621,7 +940,8 @@ router.get('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (re
|
||||
router.get('/:userId/destroyprovisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
|
||||
|
||||
try {
|
||||
const result = await db.destroy.get({"user": req.params.userId});
|
||||
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
|
||||
const result = await db.destroy.get({"user": userId});
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
|
||||
@@ -2,7 +2,7 @@ const url = require("url");
|
||||
const express = require("express");
|
||||
|
||||
import Arena from 'bull-arena';
|
||||
import { TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE } from 'qmi-cloud-common/queues';
|
||||
import { TF_APPLY_QUEUE, TF_APPLY_QSEOK_QUEUE, TF_DESTROY_QUEUE, STOP_CONTAINER_QUEUE } from 'qmi-cloud-common/queues';
|
||||
|
||||
const app = express();
|
||||
const routesApiScenarios = require('./routes/api-scenarios');
|
||||
@@ -13,6 +13,7 @@ const routesApiNotifications = require('./routes/api-notifications');
|
||||
const routesApiDivvy = require('./routes/api-divvy');
|
||||
const routesApiDeployOpts = require('./routes/api-deployopts')
|
||||
const routesApiApikeys = require('./routes/api-apikeys')
|
||||
const routesApiStats = require('./routes/api-stats')
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
const swaggerJsdoc = require('swagger-jsdoc');
|
||||
const cookieParser = require('cookie-parser');
|
||||
@@ -51,6 +52,11 @@ app.use('/arena', Arena(
|
||||
name: TF_DESTROY_QUEUE,
|
||||
hostId: 'Worker',
|
||||
redis: _getRedisConfig(process.env.REDIS_URL)
|
||||
},
|
||||
{
|
||||
name: STOP_CONTAINER_QUEUE,
|
||||
hostId: 'Worker',
|
||||
redis: _getRedisConfig(process.env.REDIS_URL)
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -85,14 +91,29 @@ app.use("/api/v1/notifications", routesApiNotifications);
|
||||
app.use("/api/v1/divvy", routesApiDivvy);
|
||||
app.use("/api/v1/deployopts", routesApiDeployOpts);
|
||||
app.use("/api/v1/apikeys", routesApiApikeys);
|
||||
app.use("/api/v1/stats", routesApiStats);
|
||||
|
||||
function _isAllowedPath(path){
|
||||
const allowedPaths = [ '/api-docs', '/arena', '/costexport', '/backendlogs', '/photos/user/' ];
|
||||
let isAllowed = false;
|
||||
for (let i=0; i<allowedPaths.length; i++) {
|
||||
if ( path.startsWith( allowedPaths[i]) ) {
|
||||
isAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isAllowed;
|
||||
}
|
||||
|
||||
/* Checking allowedPaths */
|
||||
app.get('/*',(req, res, next) =>{
|
||||
if (req.originalUrl.indexOf("/api-docs") !== -1 || req.originalUrl.indexOf("/arena") !== -1 || req.originalUrl.indexOf("/costexport") !== -1 || req.originalUrl.indexOf("/backendlogs") !== -1) {
|
||||
if ( _isAllowedPath(req.originalUrl) ) {
|
||||
return next();
|
||||
} else {
|
||||
res.sendFile(path.join(__dirname,'/../dist/qmi-cloud/index.html'));
|
||||
}
|
||||
});
|
||||
/* -----------------------*/
|
||||
|
||||
app.get('/login', passport.ensureAuthenticatedDoLogin, function(req, res) {
|
||||
res.redirect("/");
|
||||
@@ -131,25 +152,7 @@ const options = {
|
||||
name: "apiKey",
|
||||
in: "query"
|
||||
}
|
||||
},
|
||||
/*schemas: {
|
||||
"user": {
|
||||
"properties": {
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"upn": {
|
||||
"type": "string"
|
||||
},
|
||||
"oid": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
},
|
||||
security: [{
|
||||
ApiKeyAuth: []
|
||||
@@ -167,21 +170,35 @@ app.use('/costexport*', passport.ensureAuthenticatedAndAdmin, function(req, res)
|
||||
res.status(404).send("Not found");
|
||||
} else {
|
||||
res.header("Content-Type",'application/json');
|
||||
|
||||
res.sendFile(path.resolve(__dirname, '..', 'costexport', req.query.file ));
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
app.use('/photos/user/:oid', passport.ensureAuthenticated, function(req, res){
|
||||
if ( !req.params.oid ) {
|
||||
res.status(404).send("Not found");
|
||||
} else {
|
||||
var pic = path.resolve(__dirname, '..', 'photos', `${req.params.oid}.jpg` );
|
||||
if (fs.existsSync(pic)){
|
||||
res.sendFile(pic);
|
||||
} else {
|
||||
res.status(404).send();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
const specs = swaggerJsdoc(options);
|
||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
|
||||
|
||||
/**
|
||||
* Create necessary folders
|
||||
*/
|
||||
console.log("--- Create necessary folders");
|
||||
var dirs = ['/logs', '/logs/provision', '/logs/destroy'];
|
||||
|
||||
var dirs = ['/logs', '/logs/provision', '/logs/destroy', '/costexports', '/photos'];
|
||||
dirs.forEach(d => {
|
||||
if (!fs.existsSync(d)){
|
||||
console.log(`--- Creating folder '${d}' since it does not exist`);
|
||||
fs.mkdirSync(d);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
<p style="margin-top: 70px;text-align: right;">
|
||||
<a class="lui-text-info" href="/backendlogs" target="blank"><i class="fas fa-long-arrow-alt-right"></i> Backend Logs (internal)</a>
|
||||
<a class="lui-text-info" href="/backendlogs" target="_blank"><i class="fas fa-long-arrow-alt-right"></i> Backend Logs (internal)</a>
|
||||
</p>
|
||||
|
||||
<ul class="nav nav-pills nav-fill">
|
||||
@@ -10,32 +10,32 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div *ngIf="tab === 'Scenarios'">
|
||||
<div *ngIf="tab === 'scenarios'">
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-scenarios></table-scenarios>
|
||||
</div>
|
||||
<div *ngIf="tab === 'Scenario Deploy Opts'">
|
||||
<div *ngIf="tab === 'scenario-deploy-opts'">
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-subscriptions></table-subscriptions>
|
||||
</div>
|
||||
<div *ngIf="tab === 'Provisions'">
|
||||
<div *ngIf="tab === 'provisions'">
|
||||
<!--<h1>Provisions</h1>-->
|
||||
<table-provisions></table-provisions>
|
||||
</div>
|
||||
<div *ngIf="tab === 'Users'">
|
||||
<div *ngIf="tab === 'users'">
|
||||
<!--<h1>Users</h1>-->
|
||||
<table-users></table-users>
|
||||
</div>
|
||||
<div *ngIf="tab === 'Notifications'">
|
||||
<div *ngIf="tab === 'notifications'">
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-notifications></table-notifications>
|
||||
</div>
|
||||
<div *ngIf="tab === 'API keys'">
|
||||
<div *ngIf="tab === 'api-keys'">
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-apikeys></table-apikeys>
|
||||
</div>
|
||||
|
||||
<div *ngIf="tab === 'VM Types'">
|
||||
<div *ngIf="tab === 'vm-types'">
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-vmtypes></table-vmtypes>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin',
|
||||
templateUrl: './admin.component.html',
|
||||
styleUrls: ['./admin.component.scss']
|
||||
})
|
||||
export class AdminComponent implements OnInit {
|
||||
export class AdminComponent implements OnInit, OnDestroy {
|
||||
|
||||
sections = ['Provisions', 'Scenarios', 'Scenario Deploy Opts', 'Users', 'Notifications','API keys', 'VM Types'];
|
||||
sections = ['provisions', 'scenarios', 'scenario-deploy-opts', 'users', 'notifications','api-keys', 'vm-types'];
|
||||
tab : string = 'Provisions';
|
||||
private sub: any;
|
||||
|
||||
constructor() { }
|
||||
constructor( private route: ActivatedRoute, private router: Router ) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.sub = this.route.params.subscribe(params => {
|
||||
console.log("Params", params);
|
||||
this.tab = params['tab'] || 'provisions'; // (+) converts string 'id' to a number
|
||||
});
|
||||
}
|
||||
|
||||
tabSelect($event, tab) {
|
||||
$event.preventDefault();
|
||||
this.router.navigate(['/admin', tab]);
|
||||
/*$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
this.tab = tab;
|
||||
this.tab = tab;*/
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,13 +6,16 @@ import { StatsComponent } from './stats/stats.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { AuthGuard } from './services/auth.guard';
|
||||
import { FaqComponent } from './faq/faq.component';
|
||||
import { UserDashboardComponent } from './user/user-dashboard.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'home', component: HomeComponent},
|
||||
{ path: 'faq', component: FaqComponent},
|
||||
{ path: 'provisions', component: ProvisionsComponent, canActivate: [AuthGuard]},
|
||||
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard]},
|
||||
{ path: 'admin/:tab', component: AdminComponent, canActivate: [AuthGuard]},
|
||||
{ path: 'stats', component: StatsComponent, canActivate: [AuthGuard]},
|
||||
{ path: 'user/:id', component: UserDashboardComponent, canActivate: [AuthGuard]},
|
||||
{ path: '',
|
||||
redirectTo: '/home',
|
||||
pathMatch: 'full'
|
||||
|
||||
@@ -38,12 +38,14 @@ import { TableSubsComponent } from './tables/table-subscriptions.component';
|
||||
import { TableVmTypesComponent } from './tables/table-vmtypes.component';
|
||||
|
||||
import { SubscriptionsService } from './services/deployopts.service';
|
||||
import { StatsService } from './services/stats.service';
|
||||
import { TableApiKeysComponent } from './tables/table-apikeys.component';
|
||||
import { ApikeyModalComponent } from './modals/edit-apikey.component';
|
||||
import { VmTypeModalComponent } from './modals/edit-vmtype.component';
|
||||
import { StatsComponent } from './stats/stats.component';
|
||||
//import { QdtComponentComponent } from './qdt-components/qdt-components.component';
|
||||
import { ProvisionModalComponent } from './modals/edit-provision.component';
|
||||
import { UserDashboardComponent } from './user/user-dashboard.component'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
|
||||
@@ -88,6 +90,7 @@ export function markedOptions(): MarkedOptions {
|
||||
StatsComponent,
|
||||
//QdtComponentComponent,
|
||||
ProvisionModalComponent,
|
||||
UserDashboardComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@@ -108,7 +111,8 @@ export function markedOptions(): MarkedOptions {
|
||||
SubscriptionsService,
|
||||
UsersService,
|
||||
AlertService,
|
||||
AuthGuard
|
||||
AuthGuard,
|
||||
StatsService
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
@@ -1,12 +1,49 @@
|
||||
<section style="margin-top: 220px; min-height: 600px;" class="text-center">
|
||||
<div class="container">
|
||||
<img class="rounded float-right" src="assets/cloud.png" style="width: 300px;">
|
||||
<h1>QMI Cloud</h1>
|
||||
<!--<img class="rounded float-right" src="https://www.qlik.com/us/-/media/images/qlik/global/qlik-logo-2x.png" style="width: 300px;">-->
|
||||
<h1><div>Qlik Machine Images (QMI)</div><div>Cloud</div></h1>
|
||||
<p class="lead text-muted">Introducing a new way to launch scenarios based on Qlik software in the Cloud.</p>
|
||||
<p *ngIf="!user">
|
||||
<a mdbBtn href="/login" color="dark-green" mdbWavesEffect>Login <mdb-icon fas icon="sign-in-alt"></mdb-icon></a> </p>
|
||||
<p *ngIf="user">
|
||||
<a mdbBtn color="elegant" routerLink="/provisions">Your Provisions <mdb-icon fas icon="angle-right"></mdb-icon></a>
|
||||
</p>
|
||||
|
||||
<div *ngIf="stats" class="row" style="margin-top: 100px;">
|
||||
<div class="col-md-4" style="text-align: left;">
|
||||
<h1># Users</h1>
|
||||
<p class="kpiline">Registered: <span class="kpilabel">{{stats.users.total}}</span></p>
|
||||
<p class="kpiline">Active now: <span class="kpilabel">{{stats.users.activeNow}}</span></p>
|
||||
<p class="kpiline">Active last 7days: <span class="kpilabel">{{stats.users.active7days}}</span></p>
|
||||
<p class="kpiline">Active last 30days: <span class="kpilabel">{{stats.users.active30days}}</span></p>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4" style="text-align: left;">
|
||||
<h1># Provisions</h1>
|
||||
<p class="kpiline">Available scenarios: <span class="kpilabel">{{stats.scenarios.total}}</span></p>
|
||||
<p class="kpiline">Active now: <span class="kpilabel">{{stats.provisions.active}}</span> ( {{stats.provisions.running}} with running VMS )</p>
|
||||
<p class="kpiline">Total month-to-date: <span class="kpilabel">{{stats.provisions.totalCurrentMonthPeriod}}</span></p>
|
||||
<p class="kpiline">Total last month (same period): <span class="kpilabel">{{stats.provisions.totalLastMonthPerdiod}}</span></p>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4" style="text-align: left;">
|
||||
<h1># Virtual Machines</h1>
|
||||
<div *ngIf="vms">
|
||||
<p class="kpiline">Active now: <span class="kpilabel">{{vms.total}}</span></p>
|
||||
<p class="kpiline">By region:</p>
|
||||
<ul>
|
||||
<li style="font-size: 14px;">East US: <span class="kpilabel">{{vms.locations.eastus}}</span></li>
|
||||
<li style="font-size: 14px;">West Europe: <span class="kpilabel">{{vms.locations.westeurope}}</span></li>
|
||||
<li style="font-size: 14px;">Southeast Asia: <span class="kpilabel">{{vms.locations.southeastasia}}</span></li>
|
||||
</ul>
|
||||
<p class="kpiline">By OS type:</p>
|
||||
<ul>
|
||||
<li style="font-size: 14px;">Windows: <span class="kpilabel">{{vms.types.Windows}}</span></li>
|
||||
<li style="font-size: 14px;">Linux: <span class="kpilabel">{{vms.types.Linux}}</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,7 @@
|
||||
.kpilabel {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
.kpiline {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { AuthGuard } from '../services/auth.guard';
|
||||
import { StatsService } from '../services/stats.service';
|
||||
|
||||
|
||||
@Component({
|
||||
@@ -13,8 +14,10 @@ export class HomeComponent implements OnInit {
|
||||
|
||||
user;
|
||||
subs: Subscription;
|
||||
stats;
|
||||
vms;
|
||||
|
||||
constructor( private _auth: AuthGuard){
|
||||
constructor( private _auth: AuthGuard, private _stats: StatsService ){
|
||||
this.subs = this._auth.getUserInfo().subscribe( value => {
|
||||
this.user = value;
|
||||
console.log("USER", this.user);
|
||||
@@ -22,7 +25,14 @@ export class HomeComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._stats.getStats().subscribe(value => {
|
||||
this.stats = value;
|
||||
})
|
||||
|
||||
this._stats.getVms().subscribe(value => {
|
||||
console.log("vms", value);
|
||||
this.vms = value;
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
||||
@@ -22,9 +22,8 @@ export class ApikeyModalComponent implements OnInit, OnDestroy {
|
||||
constructor( public modalRef: MDBModalRef, private _usersService: UsersService ) {}
|
||||
|
||||
ngOnInit() {
|
||||
this._usersService.getUsers().subscribe(res=> {
|
||||
this._usersService.getUsers(true).subscribe(res=> {
|
||||
this.users = res.results;
|
||||
this.users = this.users.sort(function(a, b){return a.displayName.localeCompare(b.displayName);});
|
||||
if (this.apiKey) {
|
||||
this.sendData = JSON.parse(JSON.stringify(this.apiKey))
|
||||
}
|
||||
|
||||
@@ -45,9 +45,8 @@ export class ProvisionModalComponent implements OnInit, OnDestroy {
|
||||
|
||||
if ( this.currentUser.role === 'admin' || this.currentUser.role === 'superadmin' ) {
|
||||
|
||||
this._usersService.getUsers().subscribe(res=> {
|
||||
this._usersService.getUsers(true).subscribe(res=> {
|
||||
this.users = res.results;
|
||||
this.users = this.users.sort(function(a, b){return a.displayName.localeCompare(b.displayName);});
|
||||
if ( this.provision.user ) {
|
||||
this.selectedUser = this.provision.user._id;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
<input mdbInput type="number" name="text" [(ngModel)]="sendData.numSimultaneousProvisions" id="sim1" class="form-control">
|
||||
<label for="sim1" class="">Num. simultaneus provisions:</label>
|
||||
</div>
|
||||
<div class="md-form">
|
||||
<input mdbInput type="text" name="text" [(ngModel)]="support" id="support1" class="form-control">
|
||||
<label for="support1" class="">Support (emails comma separated):</label>
|
||||
</div>
|
||||
<!--<section style="padding: 20px 0px;">
|
||||
<label>Deploy options (*):</label>
|
||||
<select class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedSubscription">
|
||||
@@ -49,7 +53,16 @@
|
||||
<pre style="border: 1px solid #ccc;" contenteditable="true" (blur)="updateJson($event, 'availableProductVersions')">{{sendData.availableProductVersions | json}}</pre>
|
||||
</section>
|
||||
<section style="padding: 20px 0px; margin: 0px 20px">
|
||||
<mdb-checkbox (change)="checkOnchange($event, 'isAdminOnly')" [checked]="sendData.isAdminOnly" [default]="false"><mdb-icon fas icon="user-secret" class="grey-text" aria-hidden="true"></mdb-icon> Only for Administrators?</mdb-checkbox>
|
||||
<mdb-checkbox (change)="checkOnchange($event, 'isAdminOnly')" [checked]="sendData.isAdminOnly" [default]="false"><mdb-icon fas icon="lock" class="grey-text" aria-hidden="true"></mdb-icon> Only for Administrators?</mdb-checkbox>
|
||||
</section>
|
||||
<section *ngIf="!sendData.isAdminOnly">
|
||||
<label>Or, Administrators and selected users:</label>
|
||||
<select class="custom-select" multiple [(ngModel)]="selectedAllowedUsers">
|
||||
<option value="{{user._id}}" *ngFor="let user of allUsers">{{user.displayName}}</option>
|
||||
</select>
|
||||
<div style="font-size: 10px;">
|
||||
<i *ngFor="let u of selectedAllowedUsersObjects">{{u.displayName}}; </i>
|
||||
</div>
|
||||
</section>
|
||||
<section style="padding: 20px 0px; margin: 0px 20px">
|
||||
<mdb-checkbox (change)="checkOnchange($event, 'isExternal')" [checked]="sendData.isExternal" [default]="false"><mdb-icon fas icon="globe-americas" class="grey-text" aria-hidden="true"></mdb-icon> With External Access?</mdb-checkbox>
|
||||
@@ -64,12 +77,16 @@
|
||||
<mdb-checkbox (change)="checkOnchange($event, 'isVnetIsolated')" [checked]="sendData.isVnetIsolated" [default]="false"><mdb-icon fas icon="network-wired" class="grey-text" aria-hidden="true"></mdb-icon> Isolated Vnet (secure)?</mdb-checkbox>
|
||||
</section>-->
|
||||
<section style="padding: 20px 0px; margin: 0px 20px">
|
||||
<mdb-checkbox (change)="checkOnchange($event, 'isDisabled')" [checked]="sendData.isDisabled" [default]="false"><mdb-icon fas icon="ban" class="grey-text" aria-hidden="true"></mdb-icon> Is disabled?</mdb-checkbox>
|
||||
<mdb-checkbox (change)="checkOnchange($event, 'isDisabled')" [checked]="sendData.isDisabled" [default]="false"><mdb-icon fas icon="times-circle" class="grey-text" aria-hidden="true"></mdb-icon> Is disabled?</mdb-checkbox>
|
||||
</section>
|
||||
<div class="md-form">
|
||||
<input mdbInput type="text" name="text" [(ngModel)]="sendData.newImageName" id="image1" class="form-control">
|
||||
<label for="image1" class="">New Image Name (only for GEN scenarios):</label>
|
||||
</div>
|
||||
<div class="md-form">
|
||||
<input mdbInput type="text" name="text" [(ngModel)]="sendData.gitBranch" id="gitbranch1" class="form-control">
|
||||
<label for="gitbranch1" class="">Git branch (leave blank for default - master):</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MDBModalRef } from 'angular-bootstrap-md';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { ScenariosService } from '../services/scenarios.service';
|
||||
import { SubscriptionsService } from '../services/deployopts.service';
|
||||
import { UsersService } from '../services/users.service';
|
||||
|
||||
@Component({
|
||||
selector: 'qmi-new-scenario',
|
||||
@@ -15,7 +16,11 @@ export class ScenarioModalComponent implements OnInit, OnDestroy {
|
||||
action: Subject<any> = new Subject();
|
||||
subscriptions;
|
||||
selectedDeployOpts;
|
||||
selectedAllowedUsers;
|
||||
selectedAllowedUsersObjects = [];
|
||||
allUsers;
|
||||
labels : String = "";
|
||||
support: String = "";
|
||||
|
||||
sendData : any = {
|
||||
availableProductVersions: [{
|
||||
@@ -27,9 +32,14 @@ export class ScenarioModalComponent implements OnInit, OnDestroy {
|
||||
}]
|
||||
};
|
||||
|
||||
constructor( public modalRef: MDBModalRef, private _scenariosService: ScenariosService, private _subscriptionsService: SubscriptionsService ) {}
|
||||
constructor( public modalRef: MDBModalRef, private _usersService: UsersService, private _scenariosService: ScenariosService, private _subscriptionsService: SubscriptionsService ) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this._usersService.getUsers(true).subscribe( users => {
|
||||
this.allUsers = users.results;
|
||||
});
|
||||
|
||||
this._subscriptionsService.getSubscriptions().subscribe ( res => {
|
||||
this.subscriptions = res.results;
|
||||
console.log("SCENARIO",this.scenario);
|
||||
@@ -42,9 +52,20 @@ export class ScenarioModalComponent implements OnInit, OnDestroy {
|
||||
if ( this.scenario.deployOpts ) {
|
||||
this.selectedDeployOpts = this.scenario.deployOpts.map( item => item._id);
|
||||
}
|
||||
|
||||
if ( this.scenario.allowedUsers ) {
|
||||
this.selectedAllowedUsers = this.scenario.allowedUsers.map( item => item._id);
|
||||
this.selectedAllowedUsersObjects = JSON.parse(JSON.stringify(this.scenario.allowedUsers));
|
||||
}
|
||||
console.log("selectedAllowedUsers", this.selectedAllowedUsers);
|
||||
|
||||
if ( this.scenario.labels ) {
|
||||
this.labels = this.scenario.labels.join(",");
|
||||
}
|
||||
|
||||
if ( this.scenario.support ) {
|
||||
this.support = this.scenario.support.join(",");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,12 +76,15 @@ export class ScenarioModalComponent implements OnInit, OnDestroy {
|
||||
confirm() : void {
|
||||
let postData = this.sendData;
|
||||
postData.deployOpts = this.selectedDeployOpts;
|
||||
postData.allowedUsers = this.selectedAllowedUsers;
|
||||
|
||||
if ( this.labels.length ) {
|
||||
postData.labels = this.labels.split(",");
|
||||
}
|
||||
if ( this.support.length ) {
|
||||
postData.support = this.support.split(",");
|
||||
}
|
||||
console.log("sendData", postData);
|
||||
//this.action.next(postData);
|
||||
//console.log("Selected Deploy opts", this.selectedDeployOpts);
|
||||
if ( postData._id) {
|
||||
var id = postData._id.toString();
|
||||
postData._id = undefined;
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h3 style="text-align: center;" class="modal-title w-100">{{info._scenarioDoc.title}}</h3>
|
||||
<h3 style="text-align: center;" class="modal-title w-100">
|
||||
{{info._scenarioDoc.title}}
|
||||
<div style="font-size: 16px;">{{info.scenario}} (v{{info.scenarioVersion}})</div>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div style="text-align: right;">
|
||||
@@ -27,6 +30,7 @@
|
||||
<mdb-icon fas icon="server"></mdb-icon> {{info.vmType}} <span *ngIf="info.nodeCount">( {{info.nodeCount}} nodes )</span>
|
||||
</div>
|
||||
<div *ngFor="let item of info.vmImage | keyvalue">
|
||||
<div *ngIf="!item.value.disabled">
|
||||
<div *ngIf="item.value.version">
|
||||
<div>
|
||||
<mdb-icon fas icon="server"></mdb-icon> {{item.value.version.name}}
|
||||
@@ -41,6 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="info.isExternalAccess">
|
||||
<mdb-icon fas icon="globe-americas"></mdb-icon> External access enabled
|
||||
</div>
|
||||
@@ -49,6 +54,16 @@
|
||||
<b>{{item.key}}</b>
|
||||
<div class="mydata">{{item.value}}</div>
|
||||
</div>
|
||||
<h5 *ngIf="events" class="info-subtitle">Events</h5>
|
||||
<table *ngIf="events" mdbTable stickyHeader="true" hover="true" class="table table-sm">
|
||||
<tbody>
|
||||
<tr *ngFor="let item of events; let i = index">
|
||||
<td style="min-width:120px;">{{item.created | date: 'MMM dd, yyyy - H:mm'}}</td>
|
||||
<td style="min-width:130px;">{{item.type}}</td>
|
||||
<td>{{item.message}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" mdbBtn size="sm" color="grey" class="waves-light" aria-label="Close" (click)="modalRef.hide()" mdbWavesEffect>Close</button>
|
||||
|
||||
@@ -16,3 +16,7 @@
|
||||
.linethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 8px !important;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
||||
import { MDBModalRef } from 'angular-bootstrap-md';
|
||||
import { ProvisionsService } from '../services/provisions.service';
|
||||
|
||||
@Component({
|
||||
selector: 'qmi-modalinfo',
|
||||
@@ -10,10 +11,14 @@ export class ModalInfoComponent implements OnInit, OnDestroy {
|
||||
|
||||
info;
|
||||
|
||||
constructor( public modalRef: MDBModalRef ) {}
|
||||
events;
|
||||
|
||||
constructor( public modalRef: MDBModalRef, private _provisionsService: ProvisionsService ) {}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this._provisionsService.getEvents(this.info.user._id, this.info._id).subscribe(res=> {
|
||||
this.events = res.results;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
||||
@@ -4,21 +4,26 @@
|
||||
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title w-100 font-weight-bold">New provision</h4>
|
||||
<h5 class="modal-title w-100 font-weight-bold">
|
||||
New provision
|
||||
<div style="font-size: 14px;">{{scenario.title}}</div>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="modal-body" style="max-height: 650px; overflow: auto;">
|
||||
<div class="modal-body" style="max-height: 550px; overflow: auto;">
|
||||
<!--<h5>{{scenario.title}}</h5>-->
|
||||
<div class="needs-validation">
|
||||
<div class="md-form row" style="padding: 15px;">
|
||||
<div class="col-sm-6">
|
||||
<h5>Purpose: (*)</h5>
|
||||
<textarea [(ngModel)]="sendData.description" type="text" class="md-textarea form-control" rows="1" mdbInput placeholder="Short description or Salesforce opportunity" required></textarea>
|
||||
<textarea [(ngModel)]="sendData.description" type="text" class="md-textarea form-control" rows="1" mdbInput
|
||||
placeholder="Short description or Salesforce opportunity" required></textarea>
|
||||
</div>
|
||||
<div *ngIf="scenario.deployOpts" class="col-sm-6">
|
||||
<div>
|
||||
<label>Deploy into region: (*)</label>
|
||||
</div>
|
||||
<select id="region" class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedDeployOpts" required>
|
||||
<select id="region" class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedDeployOpts"
|
||||
required>
|
||||
<option value="" selected disabled>-- Select --</option>
|
||||
<option *ngFor="let item of scenario.deployOpts" [value]="item._id">{{item.description}}</option>
|
||||
</select>
|
||||
@@ -28,42 +33,52 @@
|
||||
|
||||
<div *ngIf="scenario.isDivvyEnabled" style="background: #f0f0f0; padding: 15px 15px; margin: 7px 0px;">
|
||||
<div>
|
||||
<h5><mdb-icon far icon="clock"></mdb-icon> VMs Running schedule</h5>
|
||||
<h5>
|
||||
<mdb-icon far icon="clock"></mdb-icon> VMs Running schedule
|
||||
</h5>
|
||||
</div>
|
||||
<p [ngClass]="{'disabled': schedule.is24x7}" style="font-size: 12px;"><i>Everyday VMs for this scenario will run as scheduled bellow</i></p>
|
||||
<p [ngClass]="{'disabled': schedule.is24x7}" style="font-size: 12px;"><i>Everyday VMs for this scenario will run
|
||||
as scheduled bellow</i></p>
|
||||
<div [ngClass]="{'disabled': schedule.is24x7}">
|
||||
Timezone is <b>{{zone}}</b> <i>(times relative to this timezone)</i>
|
||||
</div>
|
||||
<div class="row" [ngClass]="{'disabled': schedule.is24x7}">
|
||||
<div class="col-sm-6">
|
||||
<section style="padding: 10px 0px;">
|
||||
<mdb-checkbox [default]="true" [checked]="schedule.isStartupTimeEnable" (change)="checkOnchangeStartupTime($event)"><b>Startup time:</b></mdb-checkbox>
|
||||
<mdb-checkbox [default]="true" [checked]="schedule.isStartupTimeEnable"
|
||||
(change)="checkOnchangeStartupTime($event)"><b>Startup time:</b> <i [ngClass]="{'disabled': !schedule.isStartupTimeEnable}" class="utc">({{getUTCTimes().startupTime}} UTC)</i></mdb-checkbox>
|
||||
</section>
|
||||
<div [ngClass]="{'disabled': !schedule.isStartupTimeEnable}"><ngb-timepicker style="font-size: 10px;" [(ngModel)]="schedule.startupTime" [meridian]="true" [minuteStep]="15" [disabled]="schedule.is24x7 || !schedule.isStartupTimeEnable"></ngb-timepicker></div>
|
||||
<div [ngClass]="{'disabled': !schedule.isStartupTimeEnable}" class="utc">
|
||||
<i>UTC time: {{getUTCTimes().startupTime}}</i>
|
||||
<div [ngClass]="{'disabled': !schedule.isStartupTimeEnable}">
|
||||
<ngb-timepicker style="font-size: 10px;" [(ngModel)]="schedule.startupTime" [meridian]="true"
|
||||
[minuteStep]="15" [disabled]="schedule.is24x7 || !schedule.isStartupTimeEnable"></ngb-timepicker>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<section style="padding: 10px 0px;">
|
||||
<mdb-checkbox [default]="true" [checked]="true" [disabled]="true"><b>Shutdown time:</b></mdb-checkbox>
|
||||
<mdb-checkbox [default]="true" [checked]="true" [disabled]="true"><b>Shutdown time:</b> <i class="utc">({{getUTCTimes().shutdownTime}} UTC)</i></mdb-checkbox>
|
||||
</section>
|
||||
<div><ngb-timepicker style="font-size: 10px;" [(ngModel)]="schedule.shutdownTime" [meridian]="true" [minuteStep]="15" [disabled]="schedule.is24x7"></ngb-timepicker></div>
|
||||
<div class="utc">
|
||||
<i>UTC time: {{getUTCTimes().shutdownTime}}</i>
|
||||
<div>
|
||||
<ngb-timepicker style="font-size: 10px;" [(ngModel)]="schedule.shutdownTime" [meridian]="true"
|
||||
[minuteStep]="15" [disabled]="schedule.is24x7"></ngb-timepicker>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<section style="padding: 0px; margin: 0px 20px">
|
||||
<mdb-checkbox [default]="false" [checked]="schedule.is24x7" (change)="checkOnchangeSchedule($event)">Run 24x7 <i>(<mdb-icon fas icon="exclamation-triangle"></mdb-icon> requires permission from regional manager)</i></mdb-checkbox>
|
||||
<mdb-checkbox [default]="false" [checked]="schedule.is24x7" (change)="checkOnchangeSchedule($event)">Run 24x7
|
||||
<i>(<mdb-icon fas icon="exclamation-triangle"></mdb-icon> requires permission from regional manager)</i>
|
||||
</mdb-checkbox>
|
||||
</section>
|
||||
<div style="padding-left: 25px;font-size: 12px;">
|
||||
<mdb-icon fas icon="long-arrow-alt-right"></mdb-icon> VMs will run 24 hours during 7 days. Then, if 24x7 is not renewed, VMs will shutdown.
|
||||
<mdb-icon fas icon="long-arrow-alt-right"></mdb-icon> VMs will run 24 hours during 7 days. Then, if 24x7 is not
|
||||
renewed, VMs will shutdown.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding: 15px; margin: 7px 0px; background: #f0f0f0;">
|
||||
<div *ngIf="scenario.availableProductVersions && scenario.availableProductVersions.length"
|
||||
style="padding: 15px; margin: 7px 0px; background: #f0f0f0;">
|
||||
<h5 style="font-weight: 600;">
|
||||
<mdb-icon fas icon="server"></mdb-icon> Servers
|
||||
</h5>
|
||||
@@ -72,22 +87,29 @@
|
||||
{{server.product}}
|
||||
</h5>
|
||||
<div *ngIf="server.optional !== undefined">
|
||||
<mdb-checkbox style="display: inline-block;padding-left: 20px;vertical-align: top;" [default]="false" [checked]="selectedServers[server.index] || server.optional === undefined" (change)="checkOnchangeServer($event, server)" [disabled]="server.optional === undefined">Enable</mdb-checkbox>
|
||||
<mdb-checkbox style="display: inline-block;padding-left: 20px;vertical-align: top;" [default]="false"
|
||||
[checked]="selectedServers[server.index] || server.optional === undefined"
|
||||
(change)="checkOnchangeServer($event, server)" [disabled]="server.optional === undefined">Enable
|
||||
</mdb-checkbox>
|
||||
</div>
|
||||
<div *ngIf="server.versions && server.versions.length && (selectedServers[server.index] || server.optional === undefined)" >
|
||||
<div
|
||||
*ngIf="server.versions && server.versions.length && (selectedServers[server.index] || server.optional === undefined)">
|
||||
<div>
|
||||
<div>Product version:</div>
|
||||
</div>
|
||||
<select id="pversion" class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedProductVersion[server.index]" >
|
||||
<select id="pversion" class="browser-default custom-select custom-select-sm"
|
||||
[(ngModel)]="selectedProductVersion[server.index]">
|
||||
<option *ngFor="let v of server.versions" [value]="v.name">{{v.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row" *ngIf="selectedServers[server.index] || server.optional === undefined">
|
||||
<div class="row"
|
||||
*ngIf="(selectedServers[server.index] || server.optional === undefined) && selectedVmType[server.index]">
|
||||
<div class="col-sm-6">
|
||||
<div>
|
||||
<div>VM type:</div>
|
||||
</div>
|
||||
<select id="vmtype" class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedVmType[server.index]">
|
||||
<select id="vmtype" class="browser-default custom-select custom-select-sm"
|
||||
[(ngModel)]="selectedVmType[server.index]">
|
||||
<option *ngFor="let item of vmTypes" [value]="item.type">{{item.type}} ({{item.desc}})</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -95,34 +117,57 @@
|
||||
<div>
|
||||
<div>Disk size (GiB):</div>
|
||||
</div>
|
||||
<select class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedDiskSizeGb[server.index]">
|
||||
<option *ngFor="let item of [128,250,500,750,1000]" [value]="item">{{item}}</option>
|
||||
<select class="browser-default custom-select custom-select-sm"
|
||||
[(ngModel)]="selectedDiskSizeGb[server.index]">
|
||||
<option *ngFor="let item of availableDiskSizes[server.index]" [value]="item">{{item}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="server.nodeCount">
|
||||
<div>Num. nodes:</div>
|
||||
</div>
|
||||
<select *ngIf="scenario.nodeCount" class="browser-default custom-select custom-select-sm" [(ngModel)]="selectedNodeCount[server.index]">
|
||||
<select *ngIf="scenario.nodeCount" class="browser-default custom-select custom-select-sm"
|
||||
[(ngModel)]="selectedNodeCount[server.index]">
|
||||
<option *ngFor="let item of [1,2,3,4,5,6]" [value]="item">{{item}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background: #f0f0f0; padding: 15px 15px; margin: 7px 0px;">
|
||||
<div *ngIf="scenario.isExternal && scenario.availableProductVersions && scenario.availableProductVersions.length"
|
||||
style="background: #f0f0f0; padding: 15px 15px; margin: 7px 0px;">
|
||||
<div>
|
||||
<h5><mdb-icon fas icon="globe-americas"></mdb-icon> External access</h5>
|
||||
<h5>
|
||||
<mdb-icon fas icon="globe-americas"></mdb-icon> External access
|
||||
</h5>
|
||||
</div>
|
||||
<section *ngIf="scenario.isExternal" style="padding-left: 20px;">
|
||||
<mdb-checkbox [default]="false" (change)="checkOnchange($event)">Enable (<mdb-icon fas icon="exclamation-triangle"></mdb-icon> only if it's strictly necessary)</mdb-checkbox>
|
||||
<section style="padding-left: 20px;">
|
||||
<mdb-checkbox [default]="false" (change)="checkOnchange($event)">Enable (<mdb-icon fas
|
||||
icon="exclamation-triangle"></mdb-icon> only if it's strictly necessary)</mdb-checkbox>
|
||||
</section>
|
||||
<i *ngIf="!scenario.isExternal">This scenario only allows access from VPN</i>
|
||||
<!--<i *ngIf="!scenario.isExternal">This scenario only allows access from VPN</i>-->
|
||||
</div>
|
||||
|
||||
<div *ngIf="scenario.availableProductVersions && scenario.availableProductVersions.length"
|
||||
style="padding: 15px 15px; margin: 7px 0px;">
|
||||
<div>
|
||||
<h5>
|
||||
<mdb-icon fas icon="info"></mdb-icon> Important Notes:
|
||||
</h5>
|
||||
</div>
|
||||
<ul>
|
||||
<li *ngIf="scenario.isDivvyEnabled && !schedule.is24x7">VMs will auto-stop after VMs running for <b>{{scenario.allowedOnScheduleRunningDays}} days</b> (in accumulation) following the schedule. This time is reset at every <b>manual</b> stop.</li>
|
||||
<li *ngIf="!scenario.isDivvyEnabled || schedule.is24x7">VMs will auto-stop after VMs running for <b>{{scenario.allowed24x7RunningDays}} days</b>. You can extend this running period later.</li>
|
||||
<li>Provision will auto-destroy after <b *ngIf="!sendData.isExternalAccess">{{scenario.allowedInnactiveDays}} days</b><b *ngIf="sendData.isExternalAccess">{{scenario.allowedInnactiveDays/2}} days</b> of innactivity (VMs stopped
|
||||
for {{scenario.allowedInnactiveDays}} days).</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal-footer d-flex justify-content-center">
|
||||
<button mdbBtn color="dark-green" size="sm" outline="true" class="waves-effect" mdbWavesEffect (click)="modalRef.hide()">Cancel</button>
|
||||
<button mdbBtn color="dark-green" size="sm" outline="true" class="waves-effect" mdbWavesEffect
|
||||
(click)="modalRef.hide()">Cancel</button>
|
||||
<button mdbBtn color="dark-green" class="waves-light" size="sm" mdbWavesEffect (click)="confirm();">Create</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ label {
|
||||
}
|
||||
|
||||
.utc {
|
||||
padding-left: 20px;
|
||||
padding-left: 10px;
|
||||
padding-top: 5px;
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||