From 3d37f4b8e09fa01be6fce2e31e3eef95df4e1d73 Mon Sep 17 00:00:00 2001 From: zeus Date: Sun, 19 Dec 2021 17:16:03 +0200 Subject: [PATCH] vnc --- README.md | 14 +- check-open.sh | 15 + images/swarmlab-network.png | Bin 0 -> 82257 bytes .../swarmlab-mpi-autocompletion.sh | 30 + install/etc/profile.d/swarmlab-mpi.sh | 1 + install/usr/share/swarmlab.io/sec/.bashrc | 127 ++ install/usr/share/swarmlab.io/sec/.env | 7 + install/usr/share/swarmlab.io/sec/.vimrc | 15 + install/usr/share/swarmlab.io/sec/LICENSE | 614 +++++++++ .../usr/share/swarmlab.io/sec/ROOT_PASSWORD | 1 + .../share/swarmlab.io/sec/auto_update_hosts | 11 + install/usr/share/swarmlab.io/sec/commands | 13 + .../share/swarmlab.io/sec/config.default.js | 222 ++++ install/usr/share/swarmlab.io/sec/get_hosts | 8 + .../swarmlab.io/sec/install-vim-plugin.sh | 74 ++ .../usr/share/swarmlab.io/sec/package.json | 105 ++ .../sec/project/bin/start-nginx.sh | 2 + .../swarmlab.io/sec/project/bin/swarmlab-nmap | 6 + .../sec/project/config/default.conf | 44 + .../swarmlab.io/sec/project/config/nginx.conf | 29 + .../sec/project/config/supervisord.conf | 28 + .../swarmlab.io/sec/project/courses/README | 1 + .../courses/example-helloworld/app/client.js | 31 + .../courses/example-helloworld/app/mongo.js | 109 ++ .../courses/example-helloworld/app/server.js | 24 + .../courses/example-helloworld/package.json | 8 + .../project/courses/nodeAppServer/app/app.js | 107 ++ .../courses/nodeAppServer/package-lock.json | 1099 +++++++++++++++++ .../courses/nodeAppServer/package.json | 7 + .../sec/project/data-www/index.html | 121 ++ .../swarmlab.io/sec/project/hello_world.sh | 1 + .../share/swarmlab.io/sec/run-gui-backup.sh | 1 + install/usr/share/swarmlab.io/sec/run-gui.sh | 2 + .../usr/share/swarmlab.io/sec/sec_bootstrap | 74 ++ .../usr/share/swarmlab.io/sec/swarmlab-sec | 734 +++++++++++ 35 files changed, 3684 insertions(+), 1 deletion(-) create mode 100755 check-open.sh create mode 100644 images/swarmlab-network.png create mode 100644 install/etc/bash_completion.d/swarmlab-mpi-autocompletion.sh create mode 100755 install/etc/profile.d/swarmlab-mpi.sh create mode 100644 install/usr/share/swarmlab.io/sec/.bashrc create mode 100644 install/usr/share/swarmlab.io/sec/.env create mode 100644 install/usr/share/swarmlab.io/sec/.vimrc create mode 100644 install/usr/share/swarmlab.io/sec/LICENSE create mode 100644 install/usr/share/swarmlab.io/sec/ROOT_PASSWORD create mode 100755 install/usr/share/swarmlab.io/sec/auto_update_hosts create mode 100644 install/usr/share/swarmlab.io/sec/commands create mode 100644 install/usr/share/swarmlab.io/sec/config.default.js create mode 100755 install/usr/share/swarmlab.io/sec/get_hosts create mode 100644 install/usr/share/swarmlab.io/sec/install-vim-plugin.sh create mode 100644 install/usr/share/swarmlab.io/sec/package.json create mode 100755 install/usr/share/swarmlab.io/sec/project/bin/start-nginx.sh create mode 100755 install/usr/share/swarmlab.io/sec/project/bin/swarmlab-nmap create mode 100644 install/usr/share/swarmlab.io/sec/project/config/default.conf create mode 100644 install/usr/share/swarmlab.io/sec/project/config/nginx.conf create mode 100644 install/usr/share/swarmlab.io/sec/project/config/supervisord.conf create mode 100644 install/usr/share/swarmlab.io/sec/project/courses/README create mode 100644 install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/client.js create mode 100755 install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/mongo.js create mode 100644 install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/server.js create mode 100644 install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/package.json create mode 100755 install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/app/app.js create mode 100644 install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package-lock.json create mode 100755 install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package.json create mode 100644 install/usr/share/swarmlab.io/sec/project/data-www/index.html create mode 100644 install/usr/share/swarmlab.io/sec/project/hello_world.sh create mode 100755 install/usr/share/swarmlab.io/sec/run-gui-backup.sh create mode 100644 install/usr/share/swarmlab.io/sec/run-gui.sh create mode 100755 install/usr/share/swarmlab.io/sec/sec_bootstrap create mode 100755 install/usr/share/swarmlab.io/sec/swarmlab-sec diff --git a/README.md b/README.md index 2846010..058f269 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,14 @@ -# microservice-novnclite +# microservice-noVNC + + + + +## LabInstance noVNC + + +![alt text](images/swarmlab-network.png "") + + + +## Quickstart diff --git a/check-open.sh b/check-open.sh new file mode 100755 index 0000000..13e6abd --- /dev/null +++ b/check-open.sh @@ -0,0 +1,15 @@ +function EPHEMERAL_PORT() { + LOW_BOUND=49152 + RANGE=16384 + while true; do + CANDIDATE=$[$LOW_BOUND + ($RANDOM % $RANGE)] + (echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo $CANDIDATE + break + fi + done +} + +port=$(EPHEMERAL_PORT) +echo $port diff --git a/images/swarmlab-network.png b/images/swarmlab-network.png new file mode 100644 index 0000000000000000000000000000000000000000..8a346103748d30aec1df069192d96aabe800cd73 GIT binary patch literal 82257 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�n{!TeM+o# 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 dERsLc3DktIlbeieQgTE{&?|&/dev/null; then + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes + else + color_prompt= + fi +fi + +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' +fi +unset color_prompt force_color_prompt + +# If this is an xterm set the title to user@host:dir +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac + +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +# colored GCC warnings and errors +#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# some more ls aliases +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' + +# Add an "alert" alias for long running commands. Use like so: +# sleep 10; alert +alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' + +# Alias definitions. +# You may want to put all your additions into a separate file like +# ~/.bash_aliases, instead of adding them here directly. +# See /usr/share/doc/bash-doc/examples in the bash-doc package. + +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi + +if [ -d /etc/profile.d ]; then + for i in /etc/profile.d/*.sh; do + if [ -r $i ]; then + . $i + fi + done + unset i +fi + + +# enable programmable completion features (you don't need to enable +# this, if it's already enabled in /etc/bash.bashrc and /etc/profile +# sources /etc/bash.bashrc). +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi diff --git a/install/usr/share/swarmlab.io/sec/.env b/install/usr/share/swarmlab.io/sec/.env new file mode 100644 index 0000000..bb47506 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/.env @@ -0,0 +1,7 @@ +REGISTRY_ADDR=localhost +REGISTRY_PORT=5000 +IMAGE_NAME=sec +SSH_PORT=2222 +WEB_PORT=80 +WEB_PORT1=443 +WEB_PORT2=8080 diff --git a/install/usr/share/swarmlab.io/sec/.vimrc b/install/usr/share/swarmlab.io/sec/.vimrc new file mode 100644 index 0000000..7a2858b --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/.vimrc @@ -0,0 +1,15 @@ +map :NERDTreeToggle + +autocmd BufNewFile,BufRead *.vue,*.js set syntax=verilog tabstop=2|set shiftwidth=2|set noexpandtab autoindent +augroup remember_folds + autocmd! + autocmd BufWinLeave * mkview + autocmd BufWinEnter * silent! loadview +augroup END +" Useful for my Quick Notes feature in my tmuxrc +augroup QuickNotes + au BufWrite,VimLeave NOTES.otl mkview + au BufRead NOTES.otl silent loadview +augroup END +set swapfile +set dir=~/tmp diff --git a/install/usr/share/swarmlab.io/sec/LICENSE b/install/usr/share/swarmlab.io/sec/LICENSE new file mode 100644 index 0000000..82b5650 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/LICENSE @@ -0,0 +1,614 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The GNU Affero General Public License is a free, copyleft license for software +and other kinds of works, specifically designed to ensure cooperation with +the community in the case of network server software. + +The licenses for most software and other practical works are designed to take +away your freedom to share and change the works. By contrast, our General +Public Licenses are intended to guarantee your freedom to share and change +all versions of a program--to make sure it remains free software for all its +users. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for them if you wish), that +you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs, and that you know you +can do these things. + +Developers that use our General Public Licenses protect your rights with two +steps: (1) assert copyright on the software, and (2) offer you this License +which gives you legal permission to copy, distribute and/or modify the software. + +A secondary benefit of defending all users' freedom is that improvements made +in alternate versions of the program, if they receive widespread use, become +available for other developers to incorporate. Many developers of free software +are heartened and encouraged by the resulting cooperation. However, in the +case of software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and letting +the public access it on a server without ever releasing its source code to +the public. + +The GNU Affero General Public License is designed specifically to ensure that, +in such cases, the modified source code becomes available to the community. +It requires the operator of a network server to provide the source code of +the modified version running there to the users of that server. Therefore, +public use of a modified version, on a publicly accessible server, gives the +public access to the source code of the modified version. + +An older license, called the Affero General Public License and published by +Affero, was designed to accomplish similar goals. This is a different license, +not a version of the Affero GPL, but Affero has released a new version of +the Affero GPL which permits relicensing under this license. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of works, +such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this License. +Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals +or organizations. + +To "modify" a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact +copy. The resulting work is called a "modified version" of the earlier work +or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on the +Program. + +To "propagate" a work means to do anything with it that, without permission, +would make you directly or secondarily liable for infringement under applicable +copyright law, except executing it on a computer or modifying a private copy. +Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as +well. + +To "convey" a work means any kind of propagation that enables other parties +to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" to the +extent that it includes a convenient and prominently visible feature that +(1) displays an appropriate copyright notice, and (2) tells the user that +there is no warranty for the work (except to the extent that warranties are +provided), that licensees may convey the work under this License, and how +to view a copy of this License. If the interface presents a list of user commands +or options, such as a menu, a prominent item in the list meets this criterion. + + 1. Source Code. + +The "source code" for a work means the preferred form of the work for making +modifications to it. "Object code" means any non-source form of a work. + +A "Standard Interface" means an interface that either is an official standard +defined by a recognized standards body, or, in the case of interfaces specified +for a particular programming language, one that is widely used among developers +working in that language. + +The "System Libraries" of an executable work include anything, other than +the work as a whole, that (a) is included in the normal form of packaging +a Major Component, but which is not part of that Major Component, and (b) +serves only to enable use of the work with that Major Component, or to implement +a Standard Interface for which an implementation is available to the public +in source code form. A "Major Component", in this context, means a major essential +component (kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to produce +the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all the source +code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. +However, it does not include the work's System Libraries, or general-purpose +tools or generally available free programs which are used unmodified in performing +those activities but which are not part of the work. For example, Corresponding +Source includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically linked +subprograms that the work is specifically designed to require, such as by +intimate data communication or control flow between those + + subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + + The Corresponding Source for a work in source code form is that same work. + + 2. Basic Permissions. + +All rights granted under this License are granted for the term of copyright +on the Program, and are irrevocable provided the stated conditions are met. +This License explicitly affirms your unlimited permission to run the unmodified +Program. The output from running a covered work is covered by this License +only if the output, given its content, constitutes a covered work. This License +acknowledges your rights of fair use or other equivalent, as provided by copyright +law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey +covered works to others for the sole purpose of having them make modifications +exclusively for you, or provide you with facilities for running those works, +provided that you comply with the terms of this License in conveying all material +for which you do not control copyright. Those thus making or running the covered +works for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of your copyrighted +material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological measure +under any applicable law fulfilling obligations under article 11 of the WIPO +copyright treaty adopted on 20 December 1996, or similar laws prohibiting +or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention +of technological measures to the extent such circumvention is effected by +exercising rights under this License with respect to the covered work, and +you disclaim any intention to limit operation or modification of the work +as a means of enforcing, against the work's users, your or third parties' +legal rights to forbid circumvention of technological measures. + + 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you receive +it, in any medium, provided that you conspicuously and appropriately publish +on each copy an appropriate copyright notice; keep intact all notices stating +that this License and any non-permissive terms added in accord with section +7 apply to the code; keep intact all notices of the absence of any warranty; +and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you +may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to produce +it from the Program, in the form of source code under the terms of section +4, provided that you also meet all of these conditions: + +a) The work must carry prominent notices stating that you modified it, and +giving a relevant date. + +b) The work must carry prominent notices stating that it is released under +this License and any conditions added under section 7. This requirement modifies +the requirement in section 4 to "keep intact all notices". + +c) You must license the entire work, as a whole, under this License to anyone +who comes into possession of a copy. This License will therefore apply, along +with any applicable section 7 additional terms, to the whole of the work, +and all its parts, regardless of how they are packaged. This License gives +no permission to license the work in any other way, but it does not invalidate +such permission if you have separately received it. + +d) If the work has interactive user interfaces, each must display Appropriate +Legal Notices; however, if the Program has interactive interfaces that do +not display Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, +which are not by their nature extensions of the covered work, and which are +not combined with it such as to form a larger program, in or on a volume of +a storage or distribution medium, is called an "aggregate" if the compilation +and its resulting copyright are not used to limit the access or legal rights +of the compilation's users beyond what the individual works permit. Inclusion +of a covered work in an aggregate does not cause this License to apply to +the other parts of the aggregate. + + 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of sections +4 and 5, provided that you also convey the machine-readable Corresponding +Source under the terms of this License, in one of these ways: + +a) Convey the object code in, or embodied in, a physical product (including +a physical distribution medium), accompanied by the Corresponding Source fixed +on a durable physical medium customarily used for software interchange. + +b) Convey the object code in, or embodied in, a physical product (including +a physical distribution medium), accompanied by a written offer, valid for +at least three years and valid for as long as you offer spare parts or customer +support for that product model, to give anyone who possesses the object code +either (1) a copy of the Corresponding Source for all the software in the +product that is covered by this License, on a durable physical medium customarily +used for software interchange, for a price no more than your reasonable cost +of physically performing this conveying of source, or (2) access to copy the +Corresponding Source from a network server at no charge. + +c) Convey individual copies of the object code with a copy of the written +offer to provide the Corresponding Source. This alternative is allowed only +occasionally and noncommercially, and only if you received the object code +with such an offer, in accord with subsection 6b. + +d) Convey the object code by offering access from a designated place (gratis +or for a charge), and offer equivalent access to the Corresponding Source +in the same way through the same place at no further charge. You need not +require recipients to copy the Corresponding Source along with the object +code. If the place to copy the object code is a network server, the Corresponding +Source may be on a different server (operated by you or a third party) that +supports equivalent copying facilities, provided you maintain clear directions +next to the object code saying where to find the Corresponding Source. Regardless +of what server hosts the Corresponding Source, you remain obligated to ensure +that it is available for as long as needed to satisfy these requirements. + +e) Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are +being offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from +the Corresponding Source as a System Library, need not be included in conveying +the object code work. + +A "User Product" is either (1) a "consumer product", which means any tangible +personal property which is normally used for personal, family, or household +purposes, or (2) anything designed or sold for incorporation into a dwelling. +In determining whether a product is a consumer product, doubtful cases shall +be resolved in favor of coverage. For a particular product received by a particular +user, "normally used" refers to a typical or common use of that class of product, +regardless of the status of the particular user or of the way in which the +particular user actually uses, or expects or is expected to use, the product. +A product is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent the +only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, procedures, +authorization keys, or other information required to install and execute modified +versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the +continued functioning of the modified object code is in no case prevented +or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically +for use in, a User Product, and the conveying occurs as part of a transaction +in which the right of possession and use of the User Product is transferred +to the recipient in perpetuity or for a fixed term (regardless of how the +transaction is characterized), the Corresponding Source conveyed under this +section must be accompanied by the Installation Information. But this requirement +does not apply if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has been installed +in ROM). + +The requirement to provide Installation Information does not include a requirement +to continue to provide support service, warranty, or updates for a work that +has been modified or installed by the recipient, or for the User Product in +which it has been modified or installed. Access to a network may be denied +when the modification itself materially and adversely affects the operation +of the network or violates the rules and protocols for communication across +the network. + +Corresponding Source conveyed, and Installation Information provided, in accord +with this section must be in a format that is publicly documented (and with +an implementation available to the public in source code form), and must require +no special password or key for unpacking, reading or copying. + + 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this License +by making exceptions from one or more of its conditions. Additional permissions +that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part +may be used separately under those permissions, but the entire Program remains +governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when +you modify the work.) You may place additional permissions on material, added +by you to a covered work, for which you have or can give appropriate copyright +permission. + +Notwithstanding any other provision of this License, for material you add +to a covered work, you may (if authorized by the copyright holders of that +material) supplement the terms of this License with terms: + +a) Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or + +b) Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed +by works containing it; or + +c) Prohibiting misrepresentation of the origin of that material, or requiring +that modified versions of such material be marked in reasonable ways as different +from the original version; or + +d) Limiting the use for publicity purposes of names of licensors or authors +of the material; or + +e) Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or + +f) Requiring indemnification of licensors and authors of that material by +anyone who conveys the material (or modified versions of it) with contractual +assumptions of liability to the recipient, for any liability that these contractual +assumptions directly impose on those licensors and authors. + +All other non-permissive additional terms are considered "further restrictions" +within the meaning of section 10. If the Program as you received it, or any +part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. +If a license document contains a further restriction but permits relicensing +or conveying under this License, you may add to a covered work material governed +by the terms of that license document, provided that the further restriction +does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, +in the relevant source files, a statement of the additional terms that apply +to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form +of a separately written license, or stated as exceptions; the above requirements +apply either way. + + 8. Termination. + +You may not propagate or modify a covered work except as expressly provided +under this License. Any attempt otherwise to propagate or modify it is void, +and will automatically terminate your rights under this License (including +any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from +a particular copyright holder is reinstated (a) provisionally, unless and +until the copyright holder explicitly and finally terminates your license, +and (b) permanently, if the copyright holder fails to notify you of the violation +by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, +this is the first time you have received notice of violation of this License +(for any work) from that copyright holder, and you cure the violation prior +to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses +of parties who have received copies or rights from you under this License. +If your rights have been terminated and not permanently reinstated, you do +not qualify to receive new licenses for the same material under section 10. + + 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy +of the Program. Ancillary propagation of a covered work occurring solely as +a consequence of using peer-to-peer transmission to receive a copy likewise +does not require acceptance. However, nothing other than this License grants +you permission to propagate or modify any covered work. These actions infringe +copyright if you do not accept this License. Therefore, by modifying or propagating +a covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives +a license from the original licensors, to run, modify and propagate that work, +subject to this License. You are not responsible for enforcing compliance +by third parties with this License. + +An "entity transaction" is a transaction transferring control of an organization, +or substantially all assets of one, or subdividing an organization, or merging +organizations. If propagation of a covered work results from an entity transaction, +each party to that transaction who receives a copy of the work also receives +whatever licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the Corresponding +Source of the work from the predecessor in interest, if the predecessor has +it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights +granted or affirmed under this License. For example, you may not impose a +license fee, royalty, or other charge for exercise of rights granted under +this License, and you may not initiate litigation (including a cross-claim +or counterclaim in a lawsuit) alleging that any patent claim is infringed +by making, using, selling, offering for sale, or importing the Program or +any portion of it. + + 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this License +of the Program or a work on which the Program is based. The work thus licensed +is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or controlled +by the contributor, whether already acquired or hereafter acquired, that would +be infringed by some manner, permitted by this License, of making, using, +or selling its contributor version, but do not include claims that would be +infringed only as a consequence of further modification of the contributor +version. For purposes of this definition, "control" includes the right to +grant patent sublicenses in a manner consistent with the requirements of this +License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent +license under the contributor's essential patent claims, to make, use, sell, +offer for sale, import and otherwise run, modify and propagate the contents +of its contributor version. + +In the following three paragraphs, a "patent license" is any express agreement +or commitment, however denominated, not to enforce a patent (such as an express +permission to practice a patent or covenant not to s ue for patent infringement). +To "grant" such a patent license to a party means to make such an agreement +or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free +of charge and under the terms of this License, through a publicly available +network server or other readily accessible means, then you must either (1) +cause the Corresponding Source to be so available, or (2) arrange to deprive +yourself of the benefit of the patent license for this particular work, or +(3) arrange, in a manner consistent with the requirements of this License, +to extend the patent + +license to downstream recipients. "Knowingly relying" means you have actual +knowledge that, but for the patent license, your conveying the covered work +in a country, or your recipient's use of the covered work in a country, would +infringe one or more identifiable patents in that country that you have reason +to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, +you convey, or propagate by procuring conveyance of, a covered work, and grant +a patent license to some of the parties receiving the covered work authorizing +them to use, propagate, modify or convey a specific copy of the covered work, +then the patent license you grant is automatically extended to all recipients +of the covered work and works based on it. + +A patent license is "discriminatory" if it does not include within the scope +of its coverage, prohibits the exercise of, or is conditioned on the non-exercise +of one or more of the rights that are specifically granted under this License. +You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which +you make payment to the third party based on the extent of your activity of +conveying the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by you +(or copies made from those copies), or (b) primarily for and in connection +with specific products or compilations that contain the covered work, unless +you entered into that arrangement, or that patent license was granted, prior +to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available +to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from +the conditions of this License. If you cannot convey a covered work so as +to satisfy simultaneously your obligations under this License and any other +pertinent obligations, then as a consequence you may + +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey the +Program, the only way you could satisfy both those terms and this License +would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the Program, +your modified version must prominently offer all users interacting with it +remotely through a computer network (if your version supports such interaction) +an opportunity to receive the Corresponding Source of your version by providing +access to the Corresponding Source from a network server at no charge, through +some standard or customary means of facilitating copying of software. This +Corresponding Source shall include the Corresponding Source for any work covered +by version 3 of the GNU General Public License that is incorporated pursuant +to the following paragraph. + +Notwithstanding any other provision of this License, you have permission to +link or combine any covered work with a work licensed under version 3 of the +GNU General Public License into a single combined work, and to convey the +resulting work. The terms of this License will continue to apply to the part +which is the covered work, but the work with which it is combined will remain +governed by version 3 of the GNU General Public License. + + 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the +GNU Affero General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +that a certain numbered version of the GNU Affero General Public License "or +any later version" applies to it, you have the option of following the terms +and conditions either of that numbered version or of any later version published +by the Free Software Foundation. If the Program does not specify a version +number of the GNU Affero General Public License, you may choose any version +ever published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of +the GNU Affero General Public License can be used, that proxy's public statement +of acceptance of a version permanently authorizes you to choose that version +for the Program. + +Later license versions may give you additional or different permissions. However, +no additional obligations are imposed on any author or copyright holder as +a result of your choosing to follow a later version. + + 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE +LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM +PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM +AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO +USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot +be given local legal effect according to their terms, reviewing courts shall +apply local law that most closely approximates an absolute waiver of all civil +liability in connection with the Program, unless a warranty or assumption +of liability accompanies a copy of the Program in return for a fee. END OF +TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively state the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + + +Copyright (C) + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU Affero General Public License as published by the Free +Software Foundation, either version 3 of the License, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +details. + +You should have received a copy of the GNU Affero General Public License along +with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, +you should also make sure that it provides a way for users to get its source. +For example, if your program is a web application, its interface could display +a "Source" link that leads users to an archive of the code. There are many +ways you could offer source, and different solutions will be better for different +programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. For +more information on this, and how to apply and follow the GNU AGPL, see . diff --git a/install/usr/share/swarmlab.io/sec/ROOT_PASSWORD b/install/usr/share/swarmlab.io/sec/ROOT_PASSWORD new file mode 100644 index 0000000..7f3a2ef --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/ROOT_PASSWORD @@ -0,0 +1 @@ +ROOT_PASSWORD="pass" diff --git a/install/usr/share/swarmlab.io/sec/auto_update_hosts b/install/usr/share/swarmlab.io/sec/auto_update_hosts new file mode 100755 index 0000000..53c8abe --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/auto_update_hosts @@ -0,0 +1,11 @@ +#!/bin/sh + +hosts=$(get_hosts) +printf "%s" "$hosts" > "$1" + +while sleep 2 +do + current_hosts=$(get_hosts) + [ "$hosts" != "$current_hosts" ] && printf "%s" "$current_hosts" > "$1" + hosts=$current_hosts +done diff --git a/install/usr/share/swarmlab.io/sec/commands b/install/usr/share/swarmlab.io/sec/commands new file mode 100644 index 0000000..9a78e11 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/commands @@ -0,0 +1,13 @@ +create create project (swarmlab-sec create) +up start swarmlab-sec (swarmlab-sec up size=10) +scale resize swarmlab-sec (swarmlab-sec scale size=30) +reload rebuild image (swarmlab-sec reload size=15) +login login swarmlab-sec (swarmlab-sec login) +exec execute command (swarmlab-sec exec [SHELL COMMAND]) +down stop swarmlab-sec (swarmlab-sec down) +clean clean project (swarmlab-sec clean) +list show instances (swarmlab-sec list) +help show help (swarmlab-sec help) + + + diff --git a/install/usr/share/swarmlab.io/sec/config.default.js b/install/usr/share/swarmlab.io/sec/config.default.js new file mode 100644 index 0000000..b73eb84 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/config.default.js @@ -0,0 +1,222 @@ +'use strict'; + +let mongo = { + // Setting the connection string will only give access to that database + // to see more databases you need to set mongodb.admin to true or add databases to the mongodb.auth list + // It is RECOMMENDED to use connectionString instead of individual params, other options will be removed later. + // More info here: https://docs.mongodb.com/manual/reference/connection-string/ + connectionString: process.env.ME_CONFIG_MONGODB_SERVER ? '' : process.env.ME_CONFIG_MONGODB_URL, + host: '127.0.0.1', + port: '27017', + dbName: '', +}; + +// Accessing Bluemix variable to get MongoDB info +if (process.env.VCAP_SERVICES) { + const dbLabel = 'mongodb-2.4'; + const env = JSON.parse(process.env.VCAP_SERVICES); + if (env[dbLabel]) { + mongo = env[dbLabel][0].credentials; + } +} + +const basicAuthUsername = 'ME_CONFIG_BASICAUTH_USERNAME'; +const basicAuthPassword = 'ME_CONFIG_BASICAUTH_PASSWORD'; +const adminUsername = 'ME_CONFIG_MONGODB_ADMINUSERNAME'; +const adminPassword = 'ME_CONFIG_MONGODB_ADMINPASSWORD'; +const dbAuthUsername = 'ME_CONFIG_MONGODB_AUTH_USERNAME'; +const dbAuthPassword = 'ME_CONFIG_MONGODB_AUTH_PASSWORD'; + +function getFile(filePath) { + if (typeof filePath !== 'undefined' && filePath) { + const fs = require('fs'); + + try { + if (fs.existsSync(filePath)) { + return fs.readFileSync(filePath); + } + } catch (err) { + console.error('Failed to read file', filePath, err); + } + } + return null; +} + +function getFileEnv(envVariable) { + const origVar = process.env[envVariable]; + const fileVar = process.env[envVariable + '_FILE']; + if (fileVar) { + const file = getFile(fileVar); + if (file) { + return file.toString().split(/\r?\n/)[0].trim(); + } + } + return origVar; +} + +function getBinaryFileEnv(envVariable) { + const fileVar = process.env[envVariable]; + return getFile(fileVar); +} + +const meConfigMongodbServer = process.env.ME_CONFIG_MONGODB_SERVER + ? process.env.ME_CONFIG_MONGODB_SERVER.split(',') + : false; + +function getConnectionStringFromEnvVariables() { + const infos = { + // server: mongodb hostname or IP address + // for replica set, use array of string instead + server: ( + meConfigMongodbServer.length > 1 ? meConfigMongodbServer : meConfigMongodbServer[0] + ) || mongo.host, + port: process.env.ME_CONFIG_MONGODB_PORT || mongo.port, + dbName: process.env.ME_CONFIG_MONGODB_AUTH_DATABASE || mongo.dbName, + + // >>>> If you are using an admin mongodb account, or no admin account exists, fill out section below + // >>>> Using an admin account allows you to view and edit all databases, and view stats + // leave username and password empty if no admin account exists + username: getFileEnv(adminUsername) || getFileEnv(dbAuthUsername) || mongo.username, + password: getFileEnv(adminPassword) || getFileEnv(dbAuthPassword) || mongo.password, + }; + const login = infos.username ? `${infos.username}:${infos.password}@` : ''; + return `mongodb://${login}${infos.server}:${infos.port}/${infos.dbName}`; +} + +const sslCA = 'ME_CONFIG_MONGODB_CA_FILE'; +const sslCAFromEnv = getBinaryFileEnv(sslCA); + +module.exports = { + mongodb: { + // if a connection string options such as server/port/etc are ignored + connectionString: mongo.connectionString || getConnectionStringFromEnvVariables(), + + connectionOptions: { + // ssl: connect to the server using secure SSL + ssl: process.env.ME_CONFIG_MONGODB_SSL || mongo.ssl, + + // sslValidate: validate mongod server certificate against CA + sslValidate: process.env.ME_CONFIG_MONGODB_SSLVALIDATE || true, + + // sslCA: array of valid CA certificates + sslCA: sslCAFromEnv ? [sslCAFromEnv] : [], + + // autoReconnect: automatically reconnect if connection is lost + autoReconnect: true, + + // poolSize: size of connection pool (number of connections to use) + poolSize: 4, + }, + + // set admin to true if you want to turn on admin features + // if admin is true, the auth list below will be ignored + // if admin is true, you will need to enter an admin username/password below (if it is needed) + admin: process.env.ME_CONFIG_MONGODB_ENABLE_ADMIN + ? process.env.ME_CONFIG_MONGODB_ENABLE_ADMIN.toLowerCase() === 'true' + : false, + + // whitelist: hide all databases except the ones in this list (empty list for no whitelist) + whitelist: [], + + // blacklist: hide databases listed in the blacklist (empty list for no blacklist) + blacklist: [], + }, + + site: { + // baseUrl: the URL that mongo express will be located at - Remember to add the forward slash at the start and end! + baseUrl: process.env.ME_CONFIG_SITE_BASEURL || '/', + cookieKeyName: 'mongo-express', + cookieSecret: process.env.ME_CONFIG_SITE_COOKIESECRET || 'cookiesecret', + host: process.env.VCAP_APP_HOST || 'localhost', + port: process.env.VCAP_APP_PORT || 8081, + requestSizeLimit: process.env.ME_CONFIG_REQUEST_SIZE || '50mb', + sessionSecret: process.env.ME_CONFIG_SITE_SESSIONSECRET || 'sessionsecret', + sslCert: process.env.ME_CONFIG_SITE_SSL_CRT_PATH || '', + sslEnabled: process.env.ME_CONFIG_SITE_SSL_ENABLED || false, + sslKey: process.env.ME_CONFIG_SITE_SSL_KEY_PATH || '', + }, + + // set useBasicAuth to true if you want to authenticate mongo-express logins + // if admin is false, the basicAuthInfo list below will be ignored + // this will be true unless ME_CONFIG_BASICAUTH_USERNAME is set and is the empty string + useBasicAuth: getFileEnv(basicAuthUsername) !== '', + + basicAuth: { + username: getFileEnv(basicAuthUsername) || 'admin', + password: getFileEnv(basicAuthPassword) || 'pass', + }, + + options: { + // Display startup text on console + console: true, + + // documentsPerPage: how many documents you want to see at once in collection view + documentsPerPage: 10, + + // editorTheme: Name of the theme you want to use for displaying documents + // See http://codemirror.net/demo/theme.html for all examples + editorTheme: process.env.ME_CONFIG_OPTIONS_EDITORTHEME || 'rubyblue', + + // Maximum size of a single property & single row + // Reduces the risk of sending a huge amount of data when viewing collections + maxPropSize: (100 * 1000), // default 100KB + maxRowSize: (1000 * 1000), // default 1MB + + // The options below aren't being used yet + + // cmdType: the type of command line you want mongo express to run + // values: eval, subprocess + // eval - uses db.eval. commands block, so only use this if you have to + // subprocess - spawns a mongo command line as a subprocess and pipes output to mongo express + cmdType: 'eval', + + // subprocessTimeout: number of seconds of non-interaction before a subprocess is shut down + subprocessTimeout: 300, + + // readOnly: if readOnly is true, components of writing are not visible. + readOnly: process.env.ME_CONFIG_OPTIONS_READONLY + ? process.env.ME_CONFIG_OPTIONS_READONLY.toLowerCase() === 'true' + : false, + + // collapsibleJSON: if set to true, jsons will be displayed collapsible + collapsibleJSON: true, + + // collapsibleJSONDefaultUnfold: if collapsibleJSON is set to `true`, this defines default level + // to which JSONs are displayed unfolded; use number or "all" to unfold all levels + collapsibleJSONDefaultUnfold: 1, + + // gridFSEnabled: if gridFSEnabled is set to 'true', you will be able to manage uploaded files + // ( ak. grids, gridFS ) + gridFSEnabled: process.env.ME_CONFIG_SITE_GRIDFS_ENABLED + ? process.env.ME_CONFIG_SITE_GRIDFS_ENABLED.toLowerCase() === 'true' + : false, + + // logger: this object will be used to initialize router logger (morgan) + logger: {}, + + // confirmDelete: if confirmDelete is set to 'true', a modal for confirming deletion is + // displayed before deleting a document/collection + confirmDelete: false, + + // noExport: if noExport is set to true, we won't show export buttons + noExport: false, + + // noDelete: if noDelete is set to true, we won't show delete buttons + noDelete: process.env.ME_CONFIG_OPTIONS_NO_DELETE || false, + }, + + // Specify the default keyname that should be picked from a document to display in collections list. + // Keynames can be specified for every database and collection. + // If no keyname is specified, it defaults to '_id', which is a mandatory field. + // For Example : + // defaultKeyNames{ + // "world_db":{ //Database Name + // "continent":"cont_name", // collection:field + // "country":"country_name", + // "city":"name" + // } + // } + defaultKeyNames: { + + }, +}; diff --git a/install/usr/share/swarmlab.io/sec/get_hosts b/install/usr/share/swarmlab.io/sec/get_hosts new file mode 100755 index 0000000..db1d32b --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/get_hosts @@ -0,0 +1,8 @@ +#!/bin/sh + +# Include the variables that store the Docker service names +# shellcheck disable=SC1091 +. /etc/opt/service_names + +localip=$(ip addr show dev eth0 | grep "inet " | cut -d ' ' -f 6 | cut -f 1 -d '/') +nmap -sP "$localip/24" | grep Nmap | cut -d' ' -f5 | grep "_$MPI_WORKER_SERVICE_NAME_" > /project/hosts diff --git a/install/usr/share/swarmlab.io/sec/install-vim-plugin.sh b/install/usr/share/swarmlab.io/sec/install-vim-plugin.sh new file mode 100644 index 0000000..4a3801c --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/install-vim-plugin.sh @@ -0,0 +1,74 @@ +#! /usr/bin/env sh + +start_dir=$(pwd) +bin_string="export PATH=\"${PATH}:${HOME}/.vimpkg/bin\"" + +# Download the apt-vim files +curl -fSsLo ${HOME}/apt-vim/apt-vim --create-dirs \ + https://raw.githubusercontent.com/egalpin/apt-vim/master/apt-vim + +curl -fSsLo ${HOME}/apt-vim/vim_config.json \ + https://raw.githubusercontent.com/egalpin/apt-vim/master/vim_config.json + +# Add vimrc if there isn't one already +[ -f ${HOME}/.vimrc ] || touch ${HOME}/.vimrc + +# Make sure vimrc is using pathogen +if [ $(grep -c "execute pathogen#infect()" ${HOME}/.vimrc) -eq 0 ]; then + echo "execute pathogen#infect()" >> ${HOME}/.vimrc +fi +if [ $(grep -c "call pathogen#helptags()" ${HOME}/.vimrc) -eq 0 ]; then + echo "call pathogen#helptags()" >> ${HOME}/.vimrc +fi + +# Update path for executing shell +eval "$bin_string" + +added_to_profile=false +already_present=false +for rc in bashrc zshrc bash_profile; do + if [ -s "$HOME/.$rc" ]; then + if grep -q "$bin_string" "$HOME/.$rc"; then + already_present=true + else + printf "\n$bin_string\n" >> "$HOME/.$rc" + printf "== Added apt-vim PATH to '~/.$rc'\n" + added_to_profile=true + fi + fi +done + +# Execute apt-vim init +cd ${HOME}/apt-vim +python - <=16.0.0", + "npm": ">=3.0.0" + }, + "license": "MIT", + "scripts": { + "postinstall": "patch-package", + "lint": "eslint .", + "start": "cross-env NODE_ENV=production node app", + "start-dev": "concurrently --kill-others \"nodemon app --watch lib\" \"npm run build-dev\"", + "build-dev": "webpack --watch", + "build": "cross-env NODE_ENV=production webpack", + "test": "npm run mocha && npm run lint", + "mocha": "cross-env NODE_ENV=test mocha", + "test-watch": "cross-env NODE_ENV=test mocha --watch --reporter spec", + "prepublish": "npm run build" + }, + "pre-commit": [ + "test" + ], + "main": "./middleware", + "browserslist": "defaults" +} diff --git a/install/usr/share/swarmlab.io/sec/project/bin/start-nginx.sh b/install/usr/share/swarmlab.io/sec/project/bin/start-nginx.sh new file mode 100755 index 0000000..fd591f6 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/bin/start-nginx.sh @@ -0,0 +1,2 @@ +#!/bin/sh +/usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf diff --git a/install/usr/share/swarmlab.io/sec/project/bin/swarmlab-nmap b/install/usr/share/swarmlab.io/sec/project/bin/swarmlab-nmap new file mode 100755 index 0000000..5f54ecf --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/bin/swarmlab-nmap @@ -0,0 +1,6 @@ +#/bin/sh + +#ip=`nslookup hybrid-mpi_master_1.hybrid-mpi_hybrid-mpi | grep Addr | cut -d':' -f2 | grep -v 127.0.` +ip=`nslookup $NODENAME | grep Addr | cut -d':' -f2 | grep -v 127.0.` +nmap -sn -oG - $ip/24 | grep Up | grep $NODENETWORK | cut -d ' ' -f 2 + diff --git a/install/usr/share/swarmlab.io/sec/project/config/default.conf b/install/usr/share/swarmlab.io/sec/project/config/default.conf new file mode 100644 index 0000000..1072e80 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/config/default.conf @@ -0,0 +1,44 @@ +server { + listen 80; + server_name localhost; + + #charset koi8-r; + #access_log /var/log/nginx/log/host.access.log main; + + location / { + root /data/www; + index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /data/www; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} diff --git a/install/usr/share/swarmlab.io/sec/project/config/nginx.conf b/install/usr/share/swarmlab.io/sec/project/config/nginx.conf new file mode 100644 index 0000000..95505c2 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/config/nginx.conf @@ -0,0 +1,29 @@ +user www-data; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '[$time_local] $remote_user:$remote_addr "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/install/usr/share/swarmlab.io/sec/project/config/supervisord.conf b/install/usr/share/swarmlab.io/sec/project/config/supervisord.conf new file mode 100644 index 0000000..5ee7819 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/config/supervisord.conf @@ -0,0 +1,28 @@ +[unix_http_server] +file=/dev/shm/supervisor.sock ; (the path to the socket file) + +[supervisord] +logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) +pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +nodaemon=false ; (start in foreground if true;default false) +minfds=1024 ; (min. avail startup file descriptors;default 1024) +minprocs=200 ; (min. avail process descriptors;default 200) +user=root ; + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///dev/shm/supervisor.sock ; use a unix:// URL for a unix socket + +[include] +files = /etc/supervisor/conf.d/*.conf + +[program:nginx] +command=/usr/sbin/nginx +numprocs=1 +autostart=true +autorestart=true diff --git a/install/usr/share/swarmlab.io/sec/project/courses/README b/install/usr/share/swarmlab.io/sec/project/courses/README new file mode 100644 index 0000000..50cc7af --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/README @@ -0,0 +1 @@ +Course examples diff --git a/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/client.js b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/client.js new file mode 100644 index 0000000..0be0921 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/client.js @@ -0,0 +1,31 @@ + +const app = require('express')(); +const http = require('http').Server(app); +var path = require('path'); + +options = { + secure:true, + reconnect: true, + rejectUnauthorized : false +}; + + +var io2 = require('socket.io-client'); +var socket = io2.connect('http://localhost:8084', options); + +var msg2 = "c= 120"; +socket.emit('log', msg2); + +/* +var io = require('socket.io')(http); + +app.get('/log', (req, res) => { + socket.emit('log', 'send from get'); + res.send('

send

'); +}); + +http.listen(8085, () => { + console.log('listening on *:8085'); +}); +*/ + diff --git a/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/mongo.js b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/mongo.js new file mode 100755 index 0000000..11f0d50 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/mongo.js @@ -0,0 +1,109 @@ +var path = require('path'); +var app = require('express')(); +var http = require('http').Server(app); +var io = require('socket.io')(http); +const MongoClient = require('mongodb').MongoClient; + + +app.get('/test', (req, res) => { + + var user="swarmlab" + var pass="swarmlab" + + /* + use admin + db.createUser( + { + user: "test1", + pwd: 'newpass', // Or "" + roles: [ { role: "readWrite", db: "app_swarmlab" } ], + authenticationRestrictions: [ { + clientSource: ["192.168.1.7"], + serverAddress: ["192.168.80.2", "192.168.80.3", "192.168.80.4"] + } ] + } + ) + */ + + var mongourl = "mongodb://"+user+":"+pass+"@swarmlabmongo1:27017,swarmlabmongo2:27017,swarmlabmongo1:27017/app_swarmlab?replicaSet=rs0&authSource=admin&w=1" + const OPTS = { + useNewUrlParser: true, + useUnifiedTopology: true, + //poolSize: 10, + tls: false + }; + + const client = new MongoClient(mongourl,OPTS); + + client.on('serverDescriptionChanged', function(event) { + console.log('received serverDescriptionChanged'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverHeartbeatStarted', function(event) { + console.log('received serverHeartbeatStarted'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverHeartbeatSucceeded', function(event) { + console.log('received serverHeartbeatSucceeded'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverHeartbeatFailed', function(event) { + console.log('received serverHeartbeatFailed'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverOpening', function(event) { + console.log('received serverOpening'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverClosed', function(event) { + console.log('received serverClosed'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyOpening', function(event) { + console.log('received topologyOpening'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyClosed', function(event) { + console.log('received topologyClosed'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyDescriptionChanged', function(event) { + console.log('received topologyDescriptionChanged'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.connect(function(err, client) { + if(err) throw err; + + const db = client.db('app_swarmlab'); + db.collection('logs').find({}).toArray() + .then(item => { + console.log('item '+JSON.stringify(item)) + for (let i in item) { + console.log(JSON.stringify('items' + item[i])) + } + }) + }); + + res.send('

Hello world!

'); +}); + +io.on('connection', s => { + console.error('socket connection'); + + s.on('log', (data, room) => { + console.log('broadcast', data); + }); + +}); + +http.listen(8084, () => console.error('listening on http://localhost:8084/')); +console.error('socket.io example'); diff --git a/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/server.js b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/server.js new file mode 100644 index 0000000..f084d2c --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/app/server.js @@ -0,0 +1,24 @@ +var path = require('path'); +var app = require('express')(); +var http = require('http').Server(app); +var io = require('socket.io')(http); + + +app.get('/', (req, res) => { + res.send('

Hello world!

'); +}); + + +io.on('connection', s => { + console.error('socket connection'); + + s.on('log', (data, room) => { + console.log('broadcast', data); + }); + + +}); + + +http.listen(8084, () => console.error('listening on http://localhost:8084/')); +console.error('socket.io example'); diff --git a/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/package.json b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/package.json new file mode 100644 index 0000000..45af24c --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/example-helloworld/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "express": "^4.17.1", + "mongodb": "^3.6.5", + "socket.io": "^4.0.0", + "socket.io-client": "^4.0.0" + } +} diff --git a/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/app/app.js b/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/app/app.js new file mode 100755 index 0000000..f32bdc1 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/app/app.js @@ -0,0 +1,107 @@ +var express = require('express'); +var http = require('http'); +const MongoClient = require('mongodb').MongoClient; + +var PORT = 8085; + +var app = express(); +app.get('/', function(req, res) { + var RES ={} + var message = req.query["log"] + + // Connection URL + var database = "app_swarmlab" + var user = "swarmlab" + var password = "swarmlab" + var collection = "logs" + var replica_set = "rs0" + var nodes = "swarmlabmongo1:27017,swarmlabmongo2:27017,swarmlabmongo3:27017" + //var url = `mongodb://${user}:${password}@${nodes}/${database}?replicaSet=${replica_set}&authSource=admin` + + var mongourl = "mongodb://"+user+":"+password+"@swarmlabmongo1:27017,swarmlabmongo2:27017,swarmlabmongo3:27017/app_swarmlab?replicaSet=rs0&authSource=admin&w=1" + const OPTS = { + useNewUrlParser: true, + useUnifiedTopology: true, + //poolSize: 10, + tls: false + }; + + const client = new MongoClient(mongourl,OPTS); + + client.on('serverDescriptionChanged', function(event) { + console.log('received serverDescriptionChanged'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverHeartbeatStarted', function(event) { + console.log('received serverHeartbeatStarted'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverHeartbeatSucceeded', function(event) { + console.log('received serverHeartbeatSucceeded'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverHeartbeatFailed', function(event) { + console.log('received serverHeartbeatFailed'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverOpening', function(event) { + console.log('received serverOpening'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('serverClosed', function(event) { + console.log('received serverClosed'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyOpening', function(event) { + console.log('received topologyOpening'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyOpening', function(event) { + console.log('received topologyOpening'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyClosed', function(event) { + console.log('received topologyClosed'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.on('topologyDescriptionChanged', function(event) { + console.log('received topologyDescriptionChanged'); + console.log(JSON.stringify(event, null, 2)); + }); + + client.connect(function(err, client) { + if(err) throw err; + + const db = client.db('app_swarmlab'); + db.collection('logs').find({}).toArray() + .then(item => { + console.log('item '+JSON.stringify(item)) + for (let i in item) { + console.log(JSON.stringify('items' + item[i])) + } + res.send({message: message, data:item}); + + }) + }); +}); + +app.post('/', function(req, res) { + var message = req.body["log"] + console.log(JSON.stringify(message)) + //console.log(req) + res.send({message: message}); +}); + +http.Server(app).listen(PORT, function() { + console.log("HTTP server listening on port %s", PORT); +}); + diff --git a/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package-lock.json b/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package-lock.json new file mode 100644 index 0000000..27b5732 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package-lock.json @@ -0,0 +1,1099 @@ +{ + "name": "nodeAppServer", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "express": "^4.17.1", + "mongodb": "^3.6.6" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "dependencies": { + "mime-db": "1.47.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mongodb": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.6.tgz", + "integrity": "sha512-WlirMiuV1UPbej5JeCMqE93JRfZ/ZzqE7nJTwP85XzjAF4rRSeq2bGCb1cjfoHLOF06+HxADaPGqT0g3SbVT1w==", + "dependencies": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.0.2", + "safe-buffer": "^5.1.2" + }, + "engines": { + "node": ">=4" + }, + "optionalDependencies": { + "saslprep": "^1.0.0" + }, + "peerDependenciesMeta": { + "aws4": { + "optional": true + }, + "bson-ext": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "mongodb-extjson": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/optional-require": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.2.tgz", + "integrity": "sha512-HZubVd6IfHsbnpdNF/ICaSAzBUEW1TievpkjY3tB4Jnk8L7+pJ3conPzUt3Mn/6OZx9uzTDOHYPGA8/AxYHBOg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + } + }, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" + }, + "mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "requires": { + "mime-db": "1.47.0" + } + }, + "mongodb": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.6.tgz", + "integrity": "sha512-WlirMiuV1UPbej5JeCMqE93JRfZ/ZzqE7nJTwP85XzjAF4rRSeq2bGCb1cjfoHLOF06+HxADaPGqT0g3SbVT1w==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.0.2", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "optional-require": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.2.tgz", + "integrity": "sha512-HZubVd6IfHsbnpdNF/ICaSAzBUEW1TievpkjY3tB4Jnk8L7+pJ3conPzUt3Mn/6OZx9uzTDOHYPGA8/AxYHBOg==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package.json b/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package.json new file mode 100755 index 0000000..5cce523 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/courses/nodeAppServer/package.json @@ -0,0 +1,7 @@ +{ + "main": "app.js", + "dependencies": { + "express": "^4.17.1", + "mongodb": "^3.6.6" + } +} diff --git a/install/usr/share/swarmlab.io/sec/project/data-www/index.html b/install/usr/share/swarmlab.io/sec/project/data-www/index.html new file mode 100644 index 0000000..2399c7f --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/data-www/index.html @@ -0,0 +1,121 @@ + + + + + Test Page for the Nginx HTTP Server on Swarmlab.io + + + + + +

Welcome to nginx on Swarmlab.io!

+ +
+

This page is used to test the proper operation of the + nginx HTTP server after it has been + installed. If you can read this page, it means that the + web server installed at this site is working + properly.

+ +
+

Website Administrator

+
+

This is the default index.html page that + is distributed with nginx on + Swarmlab.io. It is located in + /data/www.

+ +

You should now put your content in a location of + your choice and edit the root configuration + directive in the nginx + configuration file + /etc/nginx/nginx.conf.

+ + +[ Powered by nginx ]More info here +
+
+ +
+ [ Powered by nginx ] + + [ Powered by Swarmlab.io ] +
+
+ + diff --git a/install/usr/share/swarmlab.io/sec/project/hello_world.sh b/install/usr/share/swarmlab.io/sec/project/hello_world.sh new file mode 100644 index 0000000..b5b6a5a --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/project/hello_world.sh @@ -0,0 +1 @@ +echo "Hello World" diff --git a/install/usr/share/swarmlab.io/sec/run-gui-backup.sh b/install/usr/share/swarmlab.io/sec/run-gui-backup.sh new file mode 100755 index 0000000..4a0625e --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/run-gui-backup.sh @@ -0,0 +1 @@ +docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix microservice-firefox /bin/sh -c "firefox" diff --git a/install/usr/share/swarmlab.io/sec/run-gui.sh b/install/usr/share/swarmlab.io/sec/run-gui.sh new file mode 100644 index 0000000..ca1820f --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/run-gui.sh @@ -0,0 +1,2 @@ +xhost +local:docker +docker exec -e DISPLAY=$DISPLAY microservice-firefox_masterservice_1 /bin/sh -c "firefox" diff --git a/install/usr/share/swarmlab.io/sec/sec_bootstrap b/install/usr/share/swarmlab.io/sec/sec_bootstrap new file mode 100755 index 0000000..47e7939 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/sec_bootstrap @@ -0,0 +1,74 @@ +#!/bin/sh + +ROLE="undefined" +MPI_MASTER_SERVICE_NAME="sec_masterservice" +MPI_WORKER_SERVICE_NAME="sec_workerservice" +HOSTNAMES="/etc/nethosts" + +####################### +# ARGUMENTS PARSER + +while [ "$1" != "" ]; +do + PARAM=$(echo "$1" | awk -F= '{print $1}') + VALUE=$(echo "$1" | awk -F= '{print $2}') + + case $PARAM in + role) + [ "$VALUE" ] && ROLE=$VALUE + ;; + + sec_master_service_name) + [ "$VALUE" ] && MPI_MASTER_SERVICE_NAME=$VALUE + ;; + + sec_worker_service_name) + [ "$VALUE" ] && MPI_WORKER_SERVICE_NAME=$VALUE + ;; + *) + echo "ERROR: unknown parameter \"$PARAM\"" + exit 1 + ;; + esac + shift +done + + + +cat > /etc/opt/service_names <<- EOF +MPI_MASTER_SERVICE_NAME=${MPI_MASTER_SERVICE_NAME} +MPI_WORKER_SERVICE_NAME=${MPI_WORKER_SERVICE_NAME} +EOF + +case $ROLE in + "masterservice") + + # Auto update default host file in background and dumb all output + auto_update_hosts "${HOSTNAMES}" > /dev/null 2>&1 & + #firefox + # /root/start-nginx.sh + # Start ssh server + tail -f /dev/null + #/usr/sbin/sshd -D + ;; + + + "workerservice") + + # Start ssh server in background + #/usr/sbin/sshd -D & + + # Keep trying to connect to master node and stay there indefinitely so that master node can see + # the connected hosts that are ready for MPI work + #while sleep 1 + #do + # shellcheck disable=SC2086 + # ssh -T -o "StrictHostKeyChecking no" \ + # -i "${USER_HOME}/.ssh/id_rsa" \ + # ${USER}@${MPI_MASTER_SERVICE_NAME} \ + tail -f /dev/null + #done + ;; + *) + echo 'role argument only accepts "masterservice" or "workerservice"' +esac diff --git a/install/usr/share/swarmlab.io/sec/swarmlab-sec b/install/usr/share/swarmlab.io/sec/swarmlab-sec new file mode 100755 index 0000000..61436d9 --- /dev/null +++ b/install/usr/share/swarmlab.io/sec/swarmlab-sec @@ -0,0 +1,734 @@ +#!/bin/bash + +# The MIT License (MIT) +# +# rootApostolos@swarmlab.io +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Origin: https://github.com/NLKNguyen/alpine-mpich + +set -e + +DOCKERuser="docker" +PACKAGES=$(cat </dev/null 2>&1 && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" + + +# ----------------------------------------------- +# +# Load Default config swarmlab.io +# +# ---------------------------------------------- + + +#. $DIR/.env + + +# ----------------------------------------------- +# +# Find Working dir +# +# ---------------------------------------------- + +function EPHEMERAL_PORT() { + LOW_BOUND=49152 + RANGE=16384 + while true; do + CANDIDATE=$[$LOW_BOUND + ($RANDOM % $RANGE)] + (echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo $CANDIDATE + break + fi + done +} + +servicesshport=$(EPHEMERAL_PORT) + +Wdir=$(pwd) + +if [ ! -f $Wdir/.env ]; then +cat << EOF > $Wdir/.env +REGISTRY_ADDR=localhost +REGISTRY_PORT=5000 +IMAGE_NAME=$HYBRID_NETWORK +SSH_PORT=$servicesshport +WEB_PORT=$(EPHEMERAL_PORT) +WEB_PORT1=$(EPHEMERAL_PORT) +WEB_PORT2=$(EPHEMERAL_PORT) +EOF +fi + +. $Wdir/.env + +create_dockerfile () +{ + docker pull $IMAGE_origin << ANSWERS +yes +yes +yes +ANSWERS + +. $Wdir/ROOT_PASSWORD +if [ -d "$Wdir/project" ]; then + # ----------------------------------------------- + # + # create Dockerfile + # + # ---------------------------------------------- + + search='ok' + + if [ $search == 'ok' ] + then + echo "" + echo ">>> Load Origin " + cat << EOF > $Wdir/Dockerfile + FROM $IMAGE_origin + # + USER root + + COPY $bootstrap /usr/bin + COPY $hostnames_get /usr/bin + COPY $hostnames /usr/bin + COPY install-vim-plugin.sh . + + ENV NOTVISIBLE "in users profile" + ENV USER1 docker + ENV USER_HOME /home/docker + ENV SSHDIR \${USER_HOME}/.ssh + COPY ssh/ \${SSHDIR}/ + + RUN export DEBIAN_FRONTEND=noninteractive \ + && rm -rf /usr/share/doc \ + && rm -rf /usr/share/man \ + && rm -rf /usr/share/locale \ + && mkdir -p /var/run/sshd \ + && echo 'root:pass' | chpasswd \ + && echo "export VISIBLE=now" >> /etc/profile \ + && addgroup -S docker && adduser -S docker -G docker \ + && mkdir -p /home/docker/project \ + && mkdir -p /etc/opt \ + && echo "docker:docker" | chpasswd \ + && echo "StrictHostKeyChecking no" > \${SSHDIR}/config \ + && cat \${SSHDIR}/*.pub >> \${SSHDIR}/authorized_keys \ + && chmod -R 600 \${SSHDIR}/* \ + && chown -R \${USER1}:\${USER1} \${SSHDIR} + + COPY .vimrc /home/docker + + + EXPOSE 80 + EXPOSE 6080 +EOF + fi +else + echo "" + echo "Not in Project Directory" + echo "A project directory should look like this" + echo "" + +cat <>> Load Origin " + cat << EOF > $Wdir/Dockerfile + FROM $IMAGE_origin + # + USER root + COPY $bootstrap /usr/bin + COPY $hostnames_get /usr/bin + COPY $hostnames /usr/bin + COPY install-vim-plugin.sh . + + ENV NOTVISIBLE "in users profile" + ENV USER1 docker + ENV USER_HOME /home/docker + + RUN export DEBIAN_FRONTEND=noninteractive \ + && rm -rf /usr/share/doc \ + && rm -rf /usr/share/man \ + && rm -rf /usr/share/locale \ + && mkdir -p /var/run/sshd \ + && echo 'root:pass' | chpasswd \ + && echo "export VISIBLE=now" >> /etc/profile \ + && addgroup -S docker && adduser -S docker -G docker \ + && mkdir -p /home/docker/project \ + && mkdir -p /etc/opt \ + && echo "docker:docker" | chpasswd \ + && echo "StrictHostKeyChecking no" > \${SSHDIR}/config \ + && cat \${SSHDIR}/*.pub >> \${SSHDIR}/authorized_keys \ + && chmod -R 600 \${SSHDIR}/* \ + && chown -R \${USER1}:\${USER1} \${SSHDIR} + + COPY .vimrc /home/docker + + + + EXPOSE 80 + EXPOSE 6080 +EOF +fi + + +/bin/mkdir -p $Wdir/project +/bin/mkdir -p $Wdir/logs +/bin/cp -rf $DIR/project/bin $Wdir/project +/bin/cp -rf $DIR/project/courses $Wdir/project +/bin/cp -rf $DIR/project/config $Wdir/project +/bin/cp -f $DIR/$bootstrap $Wdir/$bootstrap +/bin/cp -f $DIR/$hostnames $Wdir/$hostnames +/bin/cp -f $DIR/$hostnames_get $Wdir/$hostnames_get +/bin/cp -f $DIR/ROOT_PASSWORD $Wdir/ROOT_PASSWORD +/bin/cp -rf $DIR/.vimrc $Wdir/.vimrc +/bin/cp -rf $DIR/install-vim-plugin.sh $Wdir/install-vim-plugin.sh + + +cat << EOF > $Wdir/docker-compose.yml +version: "3" + +services: + + masterservice: + image: $IMAGE_NAME + privileged: true + environment: + - NODENAME=${NODENAME} + - NODENETWORK=${NODENETWORK} + - DISPLAY=\${DISPLAY} + cap_add: + - NET_ADMIN + user: root + #entrypoint: ["sec_bootstrap", "role=masterservice", "sec_master_service_name=masterservice", "sec_worker_service_name=workerservice"] + ports: + - "\${R_PORT1}:6080" + # - "\${R_PORT2}:3080" + networks: + - ${HYBRID_NETWORK} + volumes: + - $Wdir/project:/home/docker/project + #- $Wdir/project/package.json:/home/docker/project/package.json + #- $Wdir/project/config.default.js:/home/docker/project/config.js + #- $Wdir/$bootstrap:/usr/bin/$bootstrap + + +# workerservice: +# image: $IMAGE_NAME +# privileged: true +# environment: +# - NODENAME=${NODENAME} +# - NODENETWORK=${NODENETWORK} +# - DISPLAY=\${DISPLAY} +# cap_add: +# - NET_ADMIN +# user: root +# entrypoint: ["sec_bootstrap", "role=workerservice", "sec_master_service_name=masterservice", "sec_worker_service_name=workerservice"] +# #ports: +# # - "\${SSH_PORT}:22" +# networks: +# - ${HYBRID_NETWORK} +# volumes: +# - $Wdir/project:/home/docker/project +# - $Wdir/project/data-www:/data-www +# - $Wdir/project/config/nginx.conf:/etc/nginx/nginx.conf +# - $Wdir/project/config/default.conf:/etc/nginx/conf.d/default.conf +# - $Wdir/project/config/supervisord.conf:/etc/supervisor/supervisord.conf + +networks: + ${HYBRID_NETWORK}: +EOF + +#/bin/cp -rf $DIR/ssh $Wdir + +cat << EOF > $Wdir/stop.sh +../install/usr/share/swarmlab.io/sec/swarmlab-sec down +EOF + +cat << EOF > $Wdir/container-stop.sh +docker stop \$1 +docker container rm \$1 +EOF + +cat < CLEAN UP SWARMLAB" + + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose down" + printf "\\n" + + docker-compose down +} + +up_registry () +{ + printf "\\n\\n===> SPIN UP REGISTRY" + + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose up -d registry" + printf "\\n" + + #docker stop swarmlab-registry || true && docker rm swarmlab-registry || true # remove for microservices + docker container prune --force + docker-compose up --no-recreate -d registry +} + +generate_ssh_keys () +{ + if [ -f ssh/id_rsa ] && [ -f ssh/id_rsa.pub ]; then + return 0 + fi + + printf "\\n\\n===> GENERATE SSH KEYS \\n\\n" + + echo "$ mkdir -p ssh/ " + printf "\\n" + mkdir -p ssh/ + + echo "$ ssh-keygen -f ssh/id_rsa -t rsa -N ''" + printf "\\n" + ssh-keygen -f ssh/id_rsa -t rsa -N '' +} + +build_and_push_image () +{ + printf "\\n\\n===> BUILD IMAGE" + printf "\\n%s\\n" "$HEADER" + echo "$ docker build -t \"$IMAGE_NAME\" ." + printf "\\n" + #docker build -t "$REGISTRY_ADDR:$REGISTRY_PORT/$IMAGE_NAME" . + docker build --force-rm --pull -t "$IMAGE_NAME" . + +} + +up_master () +{ + printf "\\n\\n===> SPIN UP MASTER NODE" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose up -d masterservice" + printf "\\n" + echo "$ $IMAGE_local -d $IMAGE_origin" + printf "\\n" + + docker-compose rm -f -s -v + docker-compose up --build --remove-orphans --force-recreate -d masterservice << ANSWERS +yes +yes +yes +ANSWERS + #docker-compose up --force-recreate -d masterservice +} + + +up_workers () +{ + printf "\\n\\n===> SPIN UP WORKER NODES" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose up -d worker" + printf "\\n" + docker-compose rm -f -s -v + docker-compose up --build --force-recreate --renew-anon-volumes --remove-orphans -d workerservice + #docker-compose up --force-recreate -d workerservice + + printf "\\n" + printf "\\n%s\\n" "$HEADER" + + NUM_WORKER=$((SIZE - 1)) + echo "$ docker-compose scale workerservice=$NUM_WORKER" + printf "\\n" + docker-compose scale workerservice=${NUM_WORKER} +} + +down_master () +{ + printf "\\n\\n===> TORN DOWN MASTER NODE" + printf "\\n%s\\n" "$HEADER" + + echo "$ docker-compose stop masterservice && docker-compose rm -f masterservice" + printf "\\n" + docker-compose stop masterservice && docker-compose rm -f masterservice +} + +down_workers () +{ + printf "\\n\\n===> TORN DOWN WORKER NODES" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose stop worker && docker-compose rm -f worker" + printf "\\n" + docker-compose stop workerservice && docker-compose rm -f workerservice +} + +list () +{ + printf "\\n\\n===> LIST CONTAINERS" + printf "\\n%s\\n" "$HEADER" + echo "$ docker-compose ps" + printf "\\n" + docker-compose ps +} + + +exec_on_mpi_master_container () +{ + # shellcheck disable=SC2046 + docker exec -it -u $DOCKERuser $(docker-compose ps | grep 'masterservice'| awk 'NR==1{print $1}') "$@" +} + +prompt_ready () +{ + printf "\\n\\n===> SWARMLAB READY \\n\\n" +} + +show_instruction () +{ + echo ' ## . ' + echo ' ## ## ## == ' + echo ' ## ## ## ## ## === ' + echo ' /"""""""""""""""""\___/ === ' + echo ' ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ ' + echo ' \______ o __/ ' + echo ' \ \ __/ ' + echo ' \____\_______/ ' + echo ' ' + echo ' Swarmlab.io Hybrid ' + echo '' + echo '==============================================================' + echo '' + + echo "To run SEC programs in an interative shell:" + echo " 1. Login to masterservice node:" + echo " Using Container->connect Menou:" + echo " copy/paste and Run command" + echo "" + echo " Or using SSH with keys through exposed port:" + echo " $ ssh -o \"StrictHostKeyChecking no\" -i ssh/id_rsa -p $SSH_PORT docker@localhost" + echo ' where [localhost] could be changed to the host IP of masterservice node' + echo "" + echo " 2. Execute programs inside masterservice node, for example:" + echo " $ sudo su" + echo " # apk update" + echo " *----------------------------------------------------*" + echo " | Default hostfile of connected nodes in the swarmlab |" + echo " | To obtain hostfile manually: $ ./bin/swarmlab-nmap: > hosts |" + echo " * ---------------------------------------------------*" + echo "" + echo "" +} + + + +############################################# + +while [ "$1" != "" ]; +do + PARAM=$(echo "$1" | awk -F= '{print $1}') + VALUE=$(echo "$1" | awk -F= '{print $2}') + + case $PARAM in + help) + usage + exit + ;; + -i) + show_instruction + exit + ;; + + login) + COMMAND_LOGIN=1 + ;; + + exec) + COMMAND_EXEC=1 + shift # the rest is the shell command to run in the node + SHELL_COMMAND="$*" + break # end while loop + ;; + + up) + COMMAND_UP=1 + ;; + + create) + COMMAND_CREATE=1 + ;; + + down) + COMMAND_DOWN=1 + ;; + + reload) + COMMAND_RELOAD=1 + ;; + + scale) + COMMAND_SCALE=1 + ;; + + list) + COMMAND_LIST=1 + ;; + + clean) + COMMAND_CLEAN=1 + ;; + + size) + [ "$VALUE" ] && SIZE=$VALUE + ;; + + *) + echo "ERROR: unknown parameter \"$PARAM\"" + usage + exit 1 + ;; + esac + shift +done + + +if [ $COMMAND_UP -eq 1 ]; then + create_dockerfile + down_all + clear_all + #up_registry # remove for microservices + generate_ssh_keys + build_and_push_image # remove for microservices + up_master + #up_workers + + prompt_ready + show_instruction + +elif [ $COMMAND_CREATE -eq 1 ]; then + create_project + +elif [ $COMMAND_DOWN -eq 1 ]; then + down_all + clear_all + +elif [ $COMMAND_CLEAN -eq 1 ]; then + clear_all + + +elif [ $COMMAND_SCALE -eq 1 ]; then + create_dockerfile + down_master + down_workers + up_master + #up_workers + + prompt_ready + show_instruction + +elif [ $COMMAND_RELOAD -eq 1 ]; then + create_dockerfile + down_master + down_workers + build_and_push_image + up_master + #up_workers + + prompt_ready + show_instruction + +elif [ $COMMAND_LOGIN -eq 1 ]; then + exec_on_mpi_master_container /bin/bash + +elif [ $COMMAND_EXEC -eq 1 ]; then + create_dockerfile + exec_on_mpi_master_container ash -c "${SHELL_COMMAND}" + +elif [ $COMMAND_LIST -eq 1 ]; then + list +else + usage +fi +