diff --git a/image/Jenkinsfile b/image/Jenkinsfile new file mode 100644 index 00000000..7ca842c2 --- /dev/null +++ b/image/Jenkinsfile @@ -0,0 +1,61 @@ +pipeline { + agent any + stages { + stage('Get image') { + agent any + environment { + RPI_DONWLOAD_URL = 'https://downloads.raspberrypi.org/raspbian_lite_latest' + RPI_ZIP_NAME = 'raspbian_lite_latest.zip' + RPI_IMAGE_NAME = '2017-11-29-raspbian-stretch-lite.img' + } + steps { + sh '$WORKSPACE/deploy/image-config.sh get_image $JENKINS_HOME $RPI_ZIP_NAME $RPI_DONWLOAD_URL $RPI_IMAGE_NAME $IMAGE_NAME' + } + } + stage('Resize FS') { + environment { + SIZE = '7G' + } + steps { + sh '$WORKSPACE/deploy/image-config.sh resize_fs $SIZE $JENKINS_HOME $IMAGE_NAME $DEV_ROOTFS' + } + } + stage('Configure interfaces') { + environment { + EXECUTE_FILE = 'iface.sh' + } + steps { + sh '$WORKSPACE/deploy/image-config.sh execute $JENKINS_HOME/$IMAGE_NAME $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT $WORKSPACE/deploy/$EXECUTE_FILE' + } + } + stage('Install Apps') { + environment { + EXECUTE_FILE = 'apps.sh' + } + steps { + sh '# $WORKSPACE/deploy/image-config.sh execute $JENKINS_HOME/$IMAGE_NAME $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT $WORKSPACE/deploy/$EXECUTE_FILE' + } + } + stage('Install ROS') { + environment { + EXECUTE_FILE = 'ros.sh' + } + steps { + sh '# $WORKSPACE/deploy/image-config.sh execute $JENKINS_HOME/$IMAGE_NAME $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT $WORKSPACE/deploy/$EXECUTE_FILE' + } + } + stage('Publish image') { + environment { + CONFIG_FILE = 'coex-ci.conf' + } + steps { + sh '$WORKSPACE/deploy/image-config.sh publish_image $JENKINS_HOME $IMAGE_NAME $WORKSPACE $CONFIG_FILE $RELEASE_ID $RELEASE_BODY' + } + } + } + environment { + PREFIX_PATH = '/mnt' + DEV_BOOT = '/dev/disk/by-uuid/CDD4-B453' + DEV_ROOTFS = '/dev/disk/by-uuid/72bfc10d-73ec-4d9e-a54a-1cc507ee7ed2' + } +} diff --git a/image/apps.sh b/image/apps.sh new file mode 100755 index 00000000..459349dc --- /dev/null +++ b/image/apps.sh @@ -0,0 +1,99 @@ +#!/bin/bash + +################################################################################################################################## +# Установка необходимых программ +################################################################################################################################## + + +echo -e "\033[0;31m\033[1m$(date) | #1 apt update && apt upgrade\033[0m\033[0m" + +# install bootstrap tools +apt-get update +# && apt upgrade -y + + + +echo -e "\033[0;31m\033[1m$(date) | #2 Install programs\033[0m\033[0m" + +apt-get install --no-install-recommends -y \ + ipython \ + screen \ + byobu \ + nmap \ + lsof \ + python-pip \ + git \ + isc-dhcp-server \ + tmux + + + + + +echo -e "\033[0;31m\033[1m$(date) | #3 Write to /etc/wpa_supplicant/wpa_supplicant.conf\033[0m\033[0m" + +echo " +network={ + ssid=\"CLEVER\" + mode=2 + key_mgmt=WPA-PSK + psk=\"cleverwifi\" + frequency=2437 +}" >> /etc/wpa_supplicant/wpa_supplicant.conf + + + + + +echo -e "\033[0;31m\033[1m$(date) | #4 Write STATIC to /etc/dhcpcd.conf\033[0m\033[0m" + +echo " +interface wlan0 +static ip_address=192.168.11.1/24" >> /etc/dhcpcd.conf + + + + +echo -e "\033[0;31m\033[1m$(date) | #5 Write iface to /etc/default/isc-dhcp-server\033[0m\033[0m" + +# https://www.shellhacks.com/ru/sed-find-replace-string-in-file/ +sed -i 's/INTERFACESv4=\"\"/INTERFACESv4=\"wlan0\"/' /etc/default/isc-dhcp-server + + +echo -e "\033[0;31m\033[1m$(date) | #6 Write dhcp declaration subnet to /etc/dhcp/dhcpd.conf\033[0m\033[0m" + + +echo "subnet 192.168.11.0 netmask 255.255.255.0 { + range 192.168.11.11 192.168.11.254; + #option domain-name-servers 8.8.8.8; + #option domain-name "rpi.local"; + option routers 192.168.11.1; + option broadcast-address 192.168.11.255; + default-lease-time 600; + max-lease-time 7200; +}" >> /etc/dhcp/dhcpd.conf + + + +echo -e "\033[0;31m\033[1m$(date) | #7 Write start script for dhcpd to /etc/network/if-up.d/isc-dhcp-server\033[0m\033[0m" + +echo "#!/bin/sh +if [ \"\$IFACE\" = \"--all\" ]; +then sleep 10 && systemctl start isc-dhcp-server.service & +fi +" > /etc/network/if-up.d/isc-dhcp-server \ + && chmod +x /etc/network/if-up.d/isc-dhcp-server + + + +echo -e "\033[0;31m\033[1m$(date) | #8 Write magic script for rename SSID to /etc/rc.local\033[0m\033[0m" + +RENAME_SSID="sudo sed -i.OLD \"s/CLEVER/CLEVER-\$(head -c 100 /dev/urandom | xxd -ps -c 100 | sed -e 's/[^0-9]//g' | cut -c 1-4)/g\" /etc/wpa_supplicant/wpa_supplicant.conf && sudo sed -i '/sudo sed/d' /etc/rc.local && sudo reboot" + + +sed -i "19a$RENAME_SSID" /etc/rc.local + + + +echo -e "\033[0;31m\033[1m$(date) | #9 End of install programs\033[0m\033[0m" + diff --git a/image/git_release.py b/image/git_release.py new file mode 100755 index 00000000..e434aba5 --- /dev/null +++ b/image/git_release.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# +# Simple github release body-editor +# Smirnov Artem @urpylka +# +# Use: +# python git_release.py CONFIG_FILE RELEASE_ID RELEASE_BODY +# + + +from ConfigParser import SafeConfigParser +import requests, sys, urllib + +def json_wrapper(image_name, image_link, image_size, old_text): + old_text = urllib.unquote_plus(old_text) + buffer = "### Download\n* [" + image_name + ".zip](" + image_link + ") (" + image_size + ")\n\n" + old_text + js = {} + js["body"] = buffer + return js + + +def main(): + + cfgParser = SafeConfigParser() + cfgParser.read(sys.argv[1]) + + js = json_wrapper(sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[3]) + + r = requests.patch(cfgParser.get('github','url') + sys.argv[2], json=js, auth=(cfgParser.get('github','login'), cfgParser.get('github','password'))) + + if r.status_code == 200: + print("Message has been successfully added!") + else: + return 1 + +if __name__ == '__main__': + main() diff --git a/image/iface.sh b/image/iface.sh new file mode 100755 index 00000000..f4b1fb3b --- /dev/null +++ b/image/iface.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +################################################################################################################################## +# Настройка интерфейсов +################################################################################################################################## + +# вот так все в принципе должно включиться +# /usr/bin/raspi-config nonint do_i2c 0 +# /usr/bin/raspi-config nonint do_spi 0 +# /usr/bin/raspi-config nonint do_camera 0 +# /usr/bin/raspi-config nonint do_rgpio 0 +# /usr/bin/raspi-config nonint do_ssh 0 + +# по идеи эти настройки должны проводиться до по другому как сделано в prepare_image.sh + +set_config_var() { + lua - "$1" "$2" "$3" < "$3.bak" +local key=assert(arg[1]) +local value=assert(arg[2]) +local fn=assert(arg[3]) +local file=assert(io.open(fn)) +local made_change=false +for line in file:lines() do + if line:match("^#?%s*"..key.."=.*$") then + line=key.."="..value + made_change=true + end + print(line) +end + +if not made_change then + print(key.."="..value) +end +EOF + mv "$3.bak" "$3" +} + +BLACKLIST=/etc/modprobe.d/raspi-blacklist.conf +CONFIG=/boot/config.txt + +# 2. Изменить необходимые настройки + +# 2.1. Включить sshd +echo -e "\033[0;31m\033[1m$(date) | #11 Turn on sshd\033[0m\033[0m" +touch /boot/ssh + +# 2.2. Включить GPIO +# Включено по умолчанию + +# 2.3. Включить I2C +echo -e "\033[0;31m\033[1m$(date) | #12 Turn on I2C\033[0m\033[0m" + +set_config_var dtparam=i2c_arm on $CONFIG && + if ! [ -e $BLACKLIST ]; then + touch $BLACKLIST + fi + sed $BLACKLIST -i -e "s/^\(blacklist[[:space:]]*i2c[-_]bcm2708\)/#\1/" + sed /etc/modules -i -e "s/^#[[:space:]]*\(i2c[-_]dev\)/\1/" + if ! grep -q "^i2c[-_]dev" /etc/modules; then + printf "i2c-dev\n" >> /etc/modules + fi + +# 2.4. Включить SPI +echo -e "\033[0;31m\033[1m$(date) | #13 Turn on SPI\033[0m\033[0m" + +set_config_var dtparam=spi on $CONFIG && + if ! [ -e $BLACKLIST ]; then + touch $BLACKLIST + fi + sed $BLACKLIST -i -e "s/^\(blacklist[[:space:]]*spi[-_]bcm2708\)/#\1/" + +# 2.5. Включить raspicam +echo -e "\033[0;31m\033[1m$(date) | #14 Turn on raspicam\033[0m\033[0m" + +get_config_var() { + lua - "$1" "$2" <> /etc/modules +if ! grep -q "^bcm2835-v4l2" /etc/modules; then + printf "bcm2835-v4l2\n" >> /etc/modules +fi + +# 2.6. Настроить AP wifi +# 2.7. Настроить сеть на wlan +# 2.8. Настроить DHCPd на wlan + + +echo -e "\033[0;31m\033[1m$(date) | #15 End of configuring interfaces\033[0m\033[0m" diff --git a/image/image-config.sh b/image/image-config.sh new file mode 100755 index 00000000..134a3d7d --- /dev/null +++ b/image/image-config.sh @@ -0,0 +1,467 @@ +#!/bin/bash +#!/bin/sh + +# +# Script for image configure +# @smirart Smirnov Artem +# + + +# PREFIX_PATH=/mnt +# IMAGE=/home/pi/2017-11-29-raspbian-stretch-lite.img +# +# # blkid +# UUID_BOOT=CDD4-B453 +# UUID_ROOTFS=72bfc10d-73ec-4d9e-a54a-1cc507ee7ed2 +# +# # /dev/disk/by-label/boot +# DEV_BOOT=/dev/disk/by-uuid/$UUID_BOOT +# # /dev/disk/by-label$2 +# DEV_ROOTFS=/dev/disk/by-uuid/$UUID_ROOTFS + + +get_image() { + +# STATIC +# TEMPLATE: get_image $JENKINS_HOME $RPI_ZIP_NAME $RPI_DONWLOAD_URL $RPI_IMAGE_NAME $IMAGE_NAME + + echo 'Download RaspbianOS' + echo "$(date) | 1. Download raspbian lite" + if [ ! -e "$1/$2" ]; + then wget -nv -O $1/$2 $3 + fi + echo "$(date) | Downloading complete" + echo 'Unzip image' + echo "$(date) | 2. Unzip raspbian lite" + if [ ! -e "$1/$4" ]; + then unzip -uo $1/$2 -d $1 + fi + echo "$(date) | Unziping complete" + echo 'Duplicate image' + cp -f $1/$4 $1/$5 +} + + +resize_fs() { + + # STATIC + # TEMPLATE: resize_fs $SIZE $JENKINS_HOME $IMAGE_NAME $DEV_ROOTFS + + # https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D0%B6%D1%91%D0%BD%D0%BD%D1%8B%D0%B9_%D1%84%D0%B0%D0%B9%D0%BB + + # https://raspberrypi.stackexchange.com/questions/13137/how-can-i-mount-a-raspberry-pi-linux-distro-image + # fdisk -l 2017-11-29-raspbian-stretch-lite.img + # https://www.stableit.ru/2011/05/losetup.html + # -f : losetup сам выбрал loop (минуя занятые) + # -P : losetup монтирует разделы в образе как отдельные подразделы, + # например /dev/loop0p1 и /dev/loop0p2 + # --show : печатает имя устройства, например /dev/loop4 + + # http://karelzak.blogspot.ru/2015/05/resize-by-sfdisk.html + # ", +" : расширяет раздел до размеров образа + # -N 2 : выбирает раздел 2 для работы + + echo -e "\033[0;31m\033[1mTruncate image\033[0m\033[0m" \ + && truncate -s$1 $2/$3 \ + && echo "Mount loop-image: $2/$3" \ + && local DEV_IMAGE=$(losetup -Pf $2/$3 --show) \ + && sleep 0.5 \ + && echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" \ + && echo ", +" | sfdisk -N 2 $DEV_IMAGE \ + && sleep 0.5 \ + && echo -e "\033[0;31m\033[1mCheck & repair filesystem after expand partition\033[0m\033[0m" \ + && e2fsck -fvy $4 \ + && echo -e "\033[0;31m\033[1mExpand filesystem\033[0m\033[0m" \ + && resize2fs $4 \ + && echo -e "\033[0;31m\033[1mUmount loop-image\033[0m\033[0m" \ + && losetup -d $DEV_IMAGE +} + +publish_image() { + +# STATIC +# TEMPLATE: publish_image $JENKINS_HOME $IMAGE_NAME $WORKSPACE $CONFIG_FILE $RELEASE_ID $RELEASE_BODY + +# https://developer.github.com/v3/repos/releases/ +#RELEASE_BODY="### Changelog\n* Add /boot/cmdline.txt net.ifnames=0 https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/\n* Updated cophelper\n* Installed copstat" + + echo 'Zip image' \ + && zip $1/$2.zip $1/$2 \ + && echo 'Upload image' \ + && local IMAGE_LINK=$($3/deploy/yadisk.py $1/$4 $1/$2.zip) \ + && local IMAGE_SIZE=$(du -sh $1/$2.zip | awk '{ print $1 }') \ + && $3/deploy/git_release.py $1/$4 $5 $6 $2 $IMAGE_LINK $IMAGE_SIZE +} + +publish_image2() { + +# STATIC +# TEMPLATE: publish_image $JENKINS_HOME $IMAGE_NAME $WORKSPACE $CONFIG_FILE $RELEASE_ID $RELEASE_BODY + +# https://developer.github.com/v3/repos/releases/ +#RELEASE_BODY="### Changelog\n* Add /boot/cmdline.txt net.ifnames=0 https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/\n* Updated cophelper\n* Installed copstat" + + echo 'Zip image' \ + && zip $1/$2.zip $1/$2 \ + && echo 'Upload image' \ + && local IMAGE_LINK=$($3/deploy/yadisk.py $1/$4 $1/$2.zip) \ + && local IMAGE_SIZE=$(du -sh $1/$2.zip | awk '{ print $1 }') \ + && local NEW_RELEASE_BODY="### Download\n* [$2.zip]($IMAGE_LINK) ($IMAGE_SIZE)\n\n$6" \ + && local DATA="{ \"body\":\"$NEW_RELEASE_BODY\" }" \ + && curl -d "$(echo $DATA)" -u "LOGIN:PASS" --request PATCH https://api.github.com/repos/ONWER/REPO/releases/$5 +} + +mount_system() { + + # STATIC + # TEMPLATE: mount_system $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT + + # https://www.stableit.ru/2011/05/losetup.html + # -f : losetup выбирает незанятое имя устройства, например /dev/loop2 + # -P : losetup монтирует разделы в образе как отдельные подразделы, + # например /dev/loop0p1 и /dev/loop0p2 + # --show : печатает имя устройства, например /dev/loop4 + + echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" + DEV_IMAGE=$(losetup -Pf $1 --show) + sleep 0.5 + + echo -e "\033[0;31m\033[1mMount dirs $2 & $2/boot\033[0m\033[0m" + mount $3 $2 + mount $4 $2/boot + + echo -e "\033[0;31m\033[1mBind system dirs\033[0m\033[0m" + # https://github.com/debian-pi/raspbian-ua-netinst/issues/314 + echo "Mounting /proc in chroot... " + if [ ! -d $2/proc ] ; then + mkdir -p $2/proc + echo "Created $2/proc" + fi + mount -t proc -o nosuid,noexec,nodev proc $2/proc + echo "OK" + + echo "Mounting /sys in chroot... " + if [ ! -d $2/sys ] ; then + mkdir -p $2/sys + echo "Created $2/sys" + fi + mount -t sysfs -o nosuid,noexec,nodev sysfs $2/sys + echo "OK" + + echo "Mounting /dev/ and /dev/pts in chroot... " + mkdir -p -m 755 $2/dev/pts + mount -t devtmpfs -o mode=0755,nosuid devtmpfs $2/dev + mount -t devpts -o gid=5,mode=620 devpts $2/dev/pts + # mount -t devpts none "$2/dev/pts" -o ptmxmode=0666,newinstance + # ln -fs "pts/ptmx" "$2/dev/ptmx" + echo "OK" + + + # mount -o bind /dev $2/dev + # mount -t proc proc $2/proc + # mount -t devpts devpts $2/dev/pts + + # mount -t proc proc $2/proc + # mount -t sysfs sys $2/sys + # mount --bind /dev $2/dev + + echo -e "\033[0;31m\033[1mCopy DNS records\033[0m\033[0m" + cp -L /etc/resolv.conf $2/etc/resolv.conf + + # https://wiki.archlinux.org/index.php/Change_root_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9) + # http://www.unix-lab.org/posts/chroot/ + # https://habrahabr.ru/post/141012/ + # https://losst.ru/vosstanovlenie-grub2 + # http://unixteam.ru/content/virtualizaciya-ili-zapuskaem-prilozhenie-v-chroot-okruzhenii-razmyshleniya + # http://help.ubuntu.ru/wiki/%D0%B2%D0%BE%D1%81%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_grub + echo -e "\033[0;31m\033[1mEnter chroot\033[0m\033[0m" + chroot $2 /bin/bash +} + +mount_system2() { + + # STATIC + # TEMPLATE: mount_system2 $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT + + echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" + DEV_IMAGE=$(losetup -Pf $1 --show) + sleep 0.5 + + echo -e "\033[0;31m\033[1mMount dirs $2 & $2/boot\033[0m\033[0m" + mount $3 $2 + mount $4 $2/boot + + echo -e "\033[0;31m\033[1mBind system dirs\033[0m\033[0m" + echo "Mounting /proc in chroot... " + if [ ! -d $2/proc ] ; then + mkdir -p $2/proc + echo "Created $2/proc" + fi + mount -t proc -o nosuid,noexec,nodev proc $2/proc + echo "OK" + + echo "Mounting /sys in chroot... " + if [ ! -d $2/sys ] ; then + mkdir -p $2/sys + echo "Created $2/sys" + fi + mount -t sysfs -o nosuid,noexec,nodev sysfs $2/sys + echo "OK" + + echo "Mounting /dev/ and /dev/pts in chroot... " + mkdir -p -m 755 $2/dev/pts + mount -t devtmpfs -o mode=0755,nosuid devtmpfs $2/dev + mount -t devpts -o gid=5,mode=620 devpts $2/dev/pts + echo "OK" + + echo -e "\033[0;31m\033[1mCopy DNS records\033[0m\033[0m" + cp -L /etc/resolv.conf $2/etc/resolv.conf + + echo -e "\033[0;31m\033[1m$(date) | Enter chroot\033[0m\033[0m" + chroot $2 /bin/bash -c "$3" +} + +umount_system() { + + # STATIC + # TEMPLATE: umount_system $PREFIX_PATH + + echo -e "\033[0;31m\033[1m$(date) | Umount recursive dirs: $1\033[0m\033[0m" + umount -R $1 + echo -e "\033[0;31m\033[1m$(date) | Umount loop-image\033[0m\033[0m" + losetup -d $DEV_IMAGE +} + +umount_system2() { + + # STATIC + # TEMPLATE: umount_system $PREFIX_PATH + + echo -e "\033[0;31m\033[1m$(date) | Umount recursive dirs: $1\033[0m\033[0m" + umount -R $1 + echo -e "\033[0;31m\033[1m$(date) | Umount loop-image\033[0m\033[0m" + losetup -D +} + +set_config_var() { + lua - "$1" "$2" "$3" < "$3.bak" +local key=assert(arg[1]) +local value=assert(arg[2]) +local fn=assert(arg[3]) +local file=assert(io.open(fn)) +local made_change=false +for line in file:lines() do + if line:match("^#?%s*"..key.."=.*$") then + line=key.."="..value + made_change=true + end + print(line) +end + +if not made_change then + print(key.."="..value) +end +EOF + mv "$3.bak" "$3" +} + +configure_system() { + + # STATIC + # TEMPLATE: configure_system $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT + + local BLACKLIST=/etc/modprobe.d/raspi-blacklist.conf + local CONFIG=/boot/config.txt + + BLACKLIST=$2$BLACKLIST + CONFIG=$2$CONFIG + + # 1. Примонитровать образ + + # https://raspberrypi.stackexchange.com/questions/13137/how-can-i-mount-a-raspberry-pi-linux-distro-image + # mount -v -o offset=48234496 -t ext4 2017-11-29-raspbian-stretch-lite.img $PREFIX_PATH + # mount -v -o offset=4194304,sizelimit=29360128 -t vfat 2017-11-29-raspbian-stretch-lite.img $PREFIX_PATH/boot + # + # fdisk -l 2017-11-29-raspbian-stretch-lite.img + # https://www.stableit.ru/2011/05/losetup.html + # -f : losetup сам выбрал loop (минуя занятые) + # -P : losetup монтирует разделы в образе как отдельные подразделы, + # например /dev/loop0p1 и /dev/loop0p2 + # --show : печатает имя устройства, например /dev/loop4 + echo -e "\033[0;31m\033[1mMount loop-image: $1\033[0m\033[0m" + DEV_IMAGE=$(losetup -Pf $1 --show) + sleep 0.5 + + echo -e "\033[0;31m\033[1mMount dirs $2 & $2/boot\033[0m\033[0m" + mount $3 $2 + mount $4 $2/boot + + # 2. Изменить необходимые настройки + + # 2.1. Включить sshd + echo -e "\033[0;31m\033[1mTurn on sshd\033[0m\033[0m" + touch $2/boot/ssh + + # 2.2. Включить GPIO + # Включено по умолчанию + + # 2.3. Включить I2C + echo -e "\033[0;31m\033[1mTurn on I2C\033[0m\033[0m" + + set_config_var dtparam=i2c_arm on $CONFIG && + if ! [ -e $BLACKLIST ]; then + touch $BLACKLIST + fi + sed $BLACKLIST -i -e "s/^\(blacklist[[:space:]]*i2c[-_]bcm2708\)/#\1/" + sed $2/etc/modules -i -e "s/^#[[:space:]]*\(i2c[-_]dev\)/\1/" + if ! grep -q "^i2c[-_]dev" $2/etc/modules; then + printf "i2c-dev\n" >> $2/etc/modules + fi + + # 2.4. Включить SPI + echo -e "\033[0;31m\033[1mTurn on SPI\033[0m\033[0m" + + set_config_var dtparam=spi on $CONFIG && + if ! [ -e $BLACKLIST ]; then + touch $BLACKLIST + fi + sed $BLACKLIST -i -e "s/^\(blacklist[[:space:]]*spi[-_]bcm2708\)/#\1/" + + # 2.5. Включить raspicam + # Включена по умолчанию вроде как + + # 2.6. Настроить AP wifi + # 2.7. Настроить сеть на wlan + # 2.8. Настроить DHCPd на wlan + + # Отмонтировать образ + umount_system $2 +} + + +prepare_fs() { + + # STATIC + # TEMPLATE: prepare_fs $IMAGE $SIZE + + date + # Удаляем старый образ + # -f : не выводить ошибки, если файла нет + rm -f $1 + # Копируем origin образ + # --progress : Вывод прогресс-бара + rsync --progress -av $1.orig $1 + expand_image $1 $2G + date +} + +install_docker() { + + # STATIC + # TEMPLATE: install_docker $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT + + # https://askubuntu.com/questions/485567/unexpected-end-of-file + mount_system $1 $2 $3 $4 << EOF +#!/bin/bash +# https://www.raspberrypi.org/blog/docker-comes-to-raspberry-pi/ +curl -sSL https://get.docker.com | sh +usermod -aG docker pi +systemctl enable docker +service docker start +docker pull smirart/rpi-ros:sshd +docker run -di --restart unless-stopped -p 192.168.0.121:2202:22 -t smirart/rpi-ros:sshd +EOF + umount_system $2 +} + +test_docker() { + + # STATIC + # TEMPLATE: test_docker $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT + + mount_system $1 $2 $3 $4 << EOF +#!/bin/bash +# https://www.raspberrypi.org/blog/docker-comes-to-raspberry-pi/ +service docker start +sleep 1 +docker images +docker ps -a +EOF + umount_system $2 +} + +enter() { + + # STATIC + # TEMPLATE: enter $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT + + mount_system $1 $2 $3 $4 + umount_system $2 +} + +execute() { + + # STATIC + # TEMPLATE: execute $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT $EXECUTE_FILE + + mount_system2 $1 $2 $3 $4 "$(cat $5)" + umount_system2 $2 +} + + +# очистить history +# https://askubuntu.com/questions/191999/how-to-clear-bash-history-completely +# cat /dev/null > ~/.bash_history && history -c && exit +# +# screen in chroot +# getty tty +# https://stackoverflow.com/questions/19104894/screen-must-be-connected-to-a-terminal/25646444 +# +# docker in chroot +# service docker start +# https://forums.docker.com/t/cannot-connect-to-the-docker-daemon-is-the-docker-daemon-running-on-this-host/8925/17 + + +if [ $(whoami) != "root" ]; +then echo "" \ + && echo "********************************************************************" \ + && echo "******************** This should be run as root ********************" \ + && echo "********************************************************************" \ + && echo "" \ + && exit 1 +fi + + +echo "\$#: $#" +echo "\$1: $1" +echo "\$2: $2" +echo "\$3: $3" +echo "\$4: $4" +echo "\$5: $5" +echo "\$6: $6" + + +# test_docker +# install_docker +# prepare_fs +# configure_system + +case "$1" in + enter) + enter;; + + get_image) # get_image $JENKINS_HOME $RPI_ZIP_NAME $RPI_DONWLOAD_URL $RPI_IMAGE_NAME $IMAGE_NAME + get_image $2 $3 $4 $5 $6;; + + resize_fs) # resize_fs $SIZE $JENKINS_HOME $IMAGE_NAME $DEV_ROOTFS + resize_fs $2 $3 $4 $5;; + + publish_image) # publish_image $JENKINS_HOME $IMAGE_NAME $WORKSPACE $CONFIG_FILE $RELEASE_ID $RELEASE_BODY + publish_image $2 $3 $4 $5 $6 $7;; + + execute) # execute $IMAGE $PREFIX_PATH $DEV_ROOTFS $DEV_BOOT $EXECUTE_FILE + execute $2 $3 $4 $5 $6;; + + *) + echo "Enter one of: enter, get_image, resize_fs, publish_image, execute";; +esac diff --git a/image/ros.sh b/image/ros.sh new file mode 100755 index 00000000..63079f11 --- /dev/null +++ b/image/ros.sh @@ -0,0 +1,191 @@ +#!/bin/bash + +################################################################################################################################## +# ROS for user pi +################################################################################################################################## + +# ros http://wiki.ros.org/action/fullsearch/ROSberryPi/Installing%20ROS%20Kinetic%20on%20the%20Raspberry%20Pi +# maintainer @urpylka + +echo -e "\033[0;31m\033[1m$(date) | #0 Install ROS\033[0m\033[0m" + + + + +echo -e "\033[0;31m\033[1m$(date) | #1 Install dirmngr & add key to apt-key\033[0m\033[0m" + +# по умолчанию dirmngr отсуствует на образе и требуется для установки ключа +# http://wpblogger.su/tags/apt/ +apt install dirmngr +# setup keys +apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116 + +# setup sources.list +echo "deb http://packages.ros.org/ros/ubuntu stretch main" > /etc/apt/sources.list.d/ros-latest.list + + + + +echo -e "\033[0;31m\033[1m$(date) | #2 apt update && apt upgrade\033[0m\033[0m" + +# install bootstrap tools +apt update +# && apt upgrade -y + + + + +echo -e "\033[0;31m\033[1m$(date) | #3 Install wget, unzip, python-rosdep, python-rosinstall-generator, python-wstool, python-rosinstall, build-essential, cmake\033[0m\033[0m" + +apt-get install --no-install-recommends -y \ + wget \ + unzip \ + python-rosdep \ + python-rosinstall-generator \ + python-wstool \ + python-rosinstall \ + build-essential \ + cmake \ + libjpeg8-dev + + + +echo -e "\033[0;31m\033[1m$(date) | #4 rosdep init && rosdep update\033[0m\033[0m" + +# bootstrap rosdep +rosdep init && rosdep update + + + + +echo -e "\033[0;31m\033[1m$(date) | #5 Prepare ros_comm packages to kinetic-ros_comm-wet.rosinstall\033[0m\033[0m" + +# create catkin workspace +mkdir -p /home/pi/ros_catkin_ws && cd /home/pi/ros_catkin_ws \ + && rosinstall_generator ros_comm --rosdistro kinetic --deps --wet-only --tar > kinetic-ros_comm-wet.rosinstall \ + && wstool init src kinetic-ros_comm-wet.rosinstall + + + +echo -e "\033[0;31m\033[1m$(date) | #6 Install assimp-3.1.1 to /home/pi/ros_catkin_ws/external_src\033[0m\033[0m" + +# Unavailable Dependencies +mkdir -p /home/pi/ros_catkin_ws/external_src \ + && cd /home/pi/ros_catkin_ws/external_src \ + && wget http://sourceforge.net/projects/assimp/files/assimp-3.1/assimp-3.1.1_no_test_models.zip/download -O assimp-3.1.1_no_test_models.zip \ + && unzip assimp-3.1.1_no_test_models.zip \ + && cd assimp-3.1.1 \ + && cmake . \ + && make \ + && make install + + + + +echo -e "\033[0;31m\033[1m$(date) | #7 Prepare other ROS-packages to kinetic-custom_ros.rosinstall\033[0m\033[0m" + +cd /home/pi/ros_catkin_ws \ + && rosinstall_generator \ + actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common cv_bridge cv_camera diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs web_video_server xmlrpcpp mavros opencv3 mavros_extras \ + --rosdistro kinetic --deps --wet-only --tar > kinetic-custom_ros.rosinstall \ + && wstool merge -t src kinetic-custom_ros.rosinstall \ + && wstool update -t src + + + + +echo -e "\033[0;31m\033[1m$(date) | #8 Install dependencies apps with rosdep\033[0m\033[0m" + +# как я понял установка apt-get всяких зависимостей для ros-пакетов +# Resolving Dependencies with rosdep +cd /home/pi/ros_catkin_ws \ + && rosdep install -y --from-paths src --ignore-src --rosdistro kinetic -r --os=debian:stretch + + + + +echo -e "\033[0;31m\033[1m$(date) | #9 Refactor usb_cam in SRC\033[0m\033[0m" + +# добавление префикса с помощью двух define +# #define PIX_FMT_RGB24 AV_PIX_FMT_RGB24 +# #define PIX_FMT_YUV422P AV_PIX_FMT_YUV422P + +sed -i '/#define __STDC_CONSTANT_MACROS/a\#define PIX_FMT_RGB24 AV_PIX_FMT_RGB24\n#define PIX_FMT_YUV422P AV_PIX_FMT_YUV422P' /home/pi/ros_catkin_ws/src/usb_cam/src/usb_cam.cpp + + + +echo -e "\033[0;31m\033[1m$(date) | #10 Install GeographicLib datasets\033[0m\033[0m" + +/home/pi/ros_catkin_ws/src/mavros/mavros/scripts/install_geographiclib_datasets.sh + + + + +echo -e "\033[0;31m\033[1m$(date) | #11 Build light packages on 2 threads\033[0m\033[0m" + +# Building the catkin Workspace +cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/kinetic -j2 --pkg actionlib actionlib_msgs angles async_web_server_cpp bond bond_core bondcpp bondpy camera_calibration_parsers camera_info_manager catkin class_loader cmake_modules cpp_common diagnostic_msgs diagnostic_updater dynamic_reconfigure eigen_conversions gencpp geneus genlisp genmsg gennodejs genpy geographic_msgs geometry_msgs geometry2 image_transport libmavconn mavlink mavros_msgs message_filters message_generation message_runtime mk nav_msgs nodelet orocos_kdl pluginlib python_orocos_kdl ros ros_comm rosapi rosauth rosbag rosbag_migration_rule rosbag_storage rosbash rosboost_cfg rosbridge_library rosbridge_server rosbridge_suite rosbuild rosclean rosconsole rosconsole_bridge roscpp roscpp_serialization roscpp_traits roscreate rosgraph rosgraph_msgs roslang roslaunch roslib roslint roslisp roslz4 rosmake rosmaster rosmsg rosnode rosout rospack rosparam rospy rospy_tutorials rosserial rosserial_client rosserial_msgs rosserial_python rosservice rostest rostime rostopic rosunit roswtf sensor_msgs smclib std_msgs std_srvs stereo_msgs tf tf2 tf2_bullet tf2_eigen tf2_geometry_msgs tf2_kdl tf2_msgs tf2_py tf2_ros tf2_sensor_msgs tf2_tools topic_tools trajectory_msgs urdf urdf_parser_plugin usb_cam uuid_msgs visualization_msgs xmlrpcpp + + + + +echo -e "\033[0;31m\033[1m$(date) | #12 Build heavy packages\033[0m\033[0m" + +# Building the catkin Workspace +cd /home/pi/ros_catkin_ws && ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/kinetic -j1 --pkg mavros opencv3 cv_bridge cv_camera mavros_extras web_video_server + + + +echo -e "\033[0;31m\033[1m$(date) | #13 Create catkin_ws\033[0m\033[0m" + +mkdir -p /home/pi/catkin_ws/src \ + && cd /home/pi/catkin_ws \ + && source /opt/ros/kinetic/setup.bash \ + && catkin init \ + && wstool init /home/pi/catkin_ws/src + + + + +echo -e "\033[0;31m\033[1m$(date) | #14 Install CLEVER-BUNDLE\033[0m\033[0m" + +cd /home/pi/catkin_ws/src \ + && git clone https://github.com/CopterExpress/clever_bundle.git clever \ + && pip install wheel \ + && pip install -r /home/pi/catkin_ws/src/clever/clever/requirements.txt \ + && cd /home/pi/catkin_ws \ + && source /opt/ros/kinetic/setup.bash \ + && catkin_make -j1 \ + && systemctl enable /home/pi/catkin_ws/src/clever/deploy/roscore.service \ + && systemctl enable /home/pi/catkin_ws/src/clever/deploy/clever.service + + + +echo -e "\033[0;31m\033[1m$(date) | #15 Add mjpg-streamer at /home/pi\033[0m\033[0m" + +# https://github.com/jacksonliam/mjpg-streamer + +cd /home/pi \ + && git clone https://github.com/jacksonliam/mjpg-streamer.git \ + && cd /home/pi/mjpg-streamer/mjpg-streamer-experimental \ + && make \ + && make install + + + +echo -e "\033[0;31m\033[1m$(date) | #16 Add ENV vars\033[0m\033[0m" + +# setup environment +echo "LANG=C.UTF-8" >> /home/pi/.bashrc +echo "LC_ALL=C.UTF-8" >> /home/pi/.bashrc +echo "ROS_DISTRO=kinetic" >> /home/pi/.bashrc +echo "export ROS_IP=192.168.11.1" >> /home/pi/.bashrc + +echo "source /opt/ros/kinetic/setup.bash" >> /home/pi/.bashrc \ + && echo "source /home/pi/catkin_ws/devel/setup.bash" >> /home/pi/.bashrc + +chown -Rf pi:pi /home/pi + + + +echo -e "\033[0;31m\033[1m$(date) | #17 END of ROS INSTALLATION\033[0m\033[0m" diff --git a/image/yadisk.py b/image/yadisk.py new file mode 100755 index 00000000..b42c4c8c --- /dev/null +++ b/image/yadisk.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# +# Simple python uploader to YaDisk +# Smirnov Artem @urpylka +# +# Use: +# python yadisk.py login password file server_dir +# + +from YaDiskClient.YaDiskClient import YaDisk +import os.path, sys + +def upload(_login, _password, _server_dir, _file): + if os.path.isfile(_file): + disk = YaDisk(_login, _password) + disk.upload(_file, _server_dir + '/' + os.path.basename(_file)) + link = disk.publish_doc(_server_dir + '/' + os.path.basename(_file)) + print link + else: + print "Error: file-path is bad" + return 1 + +def main(): + if (len(sys.argv) == 5): + print "login: " + sys.argv[1] + print "password: " + sys.argv[2] + print "server_dir: " + sys.argv[3] + print "file: " + sys.argv[4] + + upload(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]) + + elif (len(sys.argv) == 3): + # print "config: " + sys.argv[1] + # print "file: " + sys.argv[2] + + if os.path.isfile(sys.argv[1]) and os.path.isfile(sys.argv[2]): + + from ConfigParser import SafeConfigParser + cfgParser = SafeConfigParser() + cfgParser.read(sys.argv[1]) + # print "login: " + cfgParser.get('yadisk','login') + # print "password: " + cfgParser.get('yadisk','password') + # print "server_dir: " + cfgParser.get('yadisk','server_dir') + + upload(cfgParser.get('yadisk','login'), cfgParser.get('yadisk','password'), cfgParser.get('yadisk','server_dir'), sys.argv[2]) + else: + print "Error: file-path or config-path is bad" + return 1 + else: + print "Error: amount of args is incorrect" + return 1 + +if __name__ == '__main__': + main()