.
This commit is contained in:
parent
f8913781ac
commit
5084f1ab92
@ -11,7 +11,7 @@ network:
|
||||
ntp: 1
|
||||
dns: 1
|
||||
www: 1
|
||||
rancher: 1
|
||||
rancher: 2
|
||||
switch: 10
|
||||
harvester: 20
|
||||
node1: 21
|
||||
|
@ -3,3 +3,4 @@ packages:
|
||||
- jq
|
||||
- htop
|
||||
- terminator
|
||||
- bridge-utils
|
||||
|
@ -1,5 +1,7 @@
|
||||
rancher:
|
||||
ca_passphrase: rancher
|
||||
root_password: rancher
|
||||
ram: 2048
|
||||
vcpus: 2
|
||||
url: docker.io/rancher/rancher
|
||||
tag: v2.6.2
|
||||
bootstrapPassword: rancher
|
||||
|
@ -1,2 +1,2 @@
|
||||
ssh:
|
||||
user-pub-keys: []
|
||||
user_pub_keys: []
|
||||
|
@ -10,7 +10,6 @@ base:
|
||||
- wireguard
|
||||
- hostapd
|
||||
- pxe
|
||||
- rancher
|
||||
- tlu-harvester
|
||||
- packages
|
||||
{% if salt['pillar.file_exists']('local.sls') %}
|
||||
|
16
salt/states/kvm/init.sls
Normal file
16
salt/states/kvm/init.sls
Normal file
@ -0,0 +1,16 @@
|
||||
Install KVM Server:
|
||||
pkg.installed:
|
||||
- name: pattern:kvm_server
|
||||
- includes: [pattern]
|
||||
|
||||
Install KVM Tools:
|
||||
pkg.installed:
|
||||
- name: pattern:kvm_tools
|
||||
- includes: [pattern]
|
||||
|
||||
Start libvirtd:
|
||||
service.running:
|
||||
- name: libvirtd
|
||||
- enable: True
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
Create the ca cnf file:
|
||||
file.managed:
|
||||
- name: /etc/rancher/ssl/rancher-ca.cnf
|
||||
- source: salt://rancher/files/rancher-ca.cnf
|
||||
- user: root
|
||||
- group: root
|
||||
- makedirs: True
|
||||
- mode: "0600"
|
||||
- dir_mode: "0755"
|
||||
|
||||
Create rancher CA key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/rancher/ssl/rancher-ca.key
|
||||
- passphrase: {{ pillar['rancher']['ca_passphrase'] }}
|
||||
- bits: 2048
|
||||
- owner: root
|
||||
- group: root
|
||||
- mode: "0600"
|
||||
|
||||
Create rancher CA certificate:
|
||||
cmd.run:
|
||||
- name: openssl req -config rancher-ca.cnf -key rancher-ca.key -new -x509 -days 3650 -sha256 -out rancher-ca.crt -passin pass:{{ pillar['rancher']['ca_passphrase'] }}
|
||||
- cwd: /etc/rancher/ssl
|
||||
- onchanges:
|
||||
- file: Create the ca cnf file
|
||||
|
||||
Create rancher-server key:
|
||||
x509.private_key_managed:
|
||||
- name: /etc/rancher/ssl/rancher-server.key
|
||||
- bits: 2048
|
||||
- owner: root
|
||||
- group: root
|
||||
- mode: "0600"
|
||||
|
||||
Create the server cnf file:
|
||||
file.managed:
|
||||
- name: /etc/rancher/ssl/rancher-server.cnf
|
||||
- source: salt://rancher/files/rancher-server.cnf.jinja
|
||||
- template: jinja
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0600"
|
||||
|
||||
Create the rancher-server signing request:
|
||||
cmd.run:
|
||||
- name: openssl req -new -key rancher-server.key -config rancher-server.cnf -out rancher-server.csr
|
||||
- cwd: /etc/rancher/ssl
|
||||
- onchanges:
|
||||
- file: Create the server cnf file
|
||||
|
||||
Set permission on rancher-server singing request:
|
||||
file.managed:
|
||||
- name: /etc/rancher/ssl/rancher-server.csr
|
||||
- replace: False
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0600"
|
||||
|
||||
Create the rancher-server certificate:
|
||||
cmd.run:
|
||||
- name: openssl x509 -req -in rancher-server.csr -CA rancher-ca.crt -CAkey rancher-ca.key -CAcreateserial -extfile rancher-server.cnf -extensions v3_req -out rancher-server.crt -days 3650 -sha256 -passin pass:{{ pillar['rancher']['ca_passphrase'] }}
|
||||
- cwd: /etc/rancher/ssl
|
||||
- onchanges:
|
||||
- cmd: Create the rancher-server signing request
|
||||
|
||||
Set permission on rancher-server certificate:
|
||||
file.managed:
|
||||
- name: /etc/rancher/ssl/rancher-server.crt
|
||||
- replace: False
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0600"
|
||||
|
||||
Set permission on rancher CA serial:
|
||||
file.managed:
|
||||
- name: /etc/rancher/ssl/rancher-ca.srl
|
||||
- replace: False
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0600"
|
@ -1,41 +0,0 @@
|
||||
[ca]
|
||||
default_ca = CA_default
|
||||
|
||||
[CA_default]
|
||||
default_bits = 2048
|
||||
x509_extensions = v3_ca
|
||||
default_days = 3650
|
||||
default_md = default
|
||||
policy = policy_optional
|
||||
copy_extensions = copy
|
||||
unique_subject = no
|
||||
|
||||
[policy_optional]
|
||||
countryName = optional
|
||||
stateOrProvinceName = optional
|
||||
localityName = optional
|
||||
organizationName = optional
|
||||
organizationalUnitName = optional
|
||||
commonName = optional
|
||||
emailAddress = optional
|
||||
|
||||
###############################################
|
||||
|
||||
[req]
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
x509_extensions = v3_ca
|
||||
string_mask = utf8only
|
||||
prompt = no
|
||||
|
||||
[v3_ca]
|
||||
basicConstraints = critical, CA:true
|
||||
nsComment = "Rancher CA Certificate"
|
||||
nsCertType = sslCA
|
||||
keyUsage = cRLSign, keyCertSign
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
|
||||
###############################################
|
||||
[ req_distinguished_name ]
|
||||
CN = Rancher Certificate Authority
|
@ -1,34 +0,0 @@
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443;
|
||||
server_name rancher.{{ pillar['network']['domain'] }};
|
||||
ssl_certificate /etc/rancher/ssl/rancher-server.crt;
|
||||
ssl_certificate_key /etc/rancher/ssl/rancher-server.key;
|
||||
location /{
|
||||
proxy_pass https://172.18.0.1:9080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_read_timeout 3600;
|
||||
proxy_set_header X-API-request-url $scheme://$host:$server_port$request_uri;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-Host $host:$server_port;
|
||||
proxy_set_header Referer $host:$server_port;
|
||||
proxy_buffering off;
|
||||
proxy_redirect off;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name rancher.{{ pillar['network']['domain'] }};
|
||||
return 301 https://rancher.{{ pillar['network']['domain'] }}$request_uri;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
[req]
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
x509_extensions = v3_server_sign
|
||||
string_mask = utf8only
|
||||
prompt = no
|
||||
req_extensions = v3_req
|
||||
|
||||
[v3_server_sign]
|
||||
basicConstraints = CA:false
|
||||
nsComment = "Rancher Server Certificate"
|
||||
nsCertType = server
|
||||
keyUsage = digitalSignature, keyEncipherment, keyAgreement
|
||||
extendedKeyUsage = serverAuth, clientAuth
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid,issuer:always
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:false
|
||||
keyUsage = digitalSignature, keyEncipherment, keyAgreement
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[req_distinguished_name]
|
||||
CN = rancher.{{ pillar['network']['domain'] }}
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = rancher.{{ pillar['network']['domain'] }}
|
||||
IP.1 = {{ pillar['network']['ip'] }}
|
@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=Rancher podman container
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Restart=on-failure
|
||||
ExecStart=/usr/bin/podman start -a rancher
|
||||
ExecStop=/usr/bin/podman stop -t 120 rancher
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target default.target
|
@ -1,4 +0,0 @@
|
||||
include:
|
||||
- rancher.certs
|
||||
- rancher.server
|
||||
- rancher.nginx
|
@ -1,14 +0,0 @@
|
||||
proxy configuration for nginx:
|
||||
file.managed:
|
||||
- name: /etc/nginx/vhosts.d/rancher-proxy.conf
|
||||
- source: salt://rancher/files/rancher-proxy.conf.jinja
|
||||
- template: jinja
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0644"
|
||||
|
||||
reload nginx:
|
||||
service.running:
|
||||
- name: nginx
|
||||
- watch:
|
||||
- file: proxy configuration for nginx
|
@ -1,52 +0,0 @@
|
||||
Create rancher systemd unit file:
|
||||
file.managed:
|
||||
- name: /etc/systemd/system/rancher.service
|
||||
- source: salt://rancher/files/rancher.service
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0644"
|
||||
|
||||
Realod systemd daemon:
|
||||
cmd.run:
|
||||
- name: systemctl daemon-reload
|
||||
- onchanges:
|
||||
- file: Create rancher systemd unit file
|
||||
|
||||
Pull rancher image:
|
||||
cmd.run:
|
||||
- name: "podman image pull {{ pillar['rancher']['url'] }}:{{ pillar['rancher']['tag'] }}"
|
||||
- unless: "podman image exists {{ pillar['rancher']['url'] }}:{{ pillar['rancher']['tag'] }}"
|
||||
|
||||
Add persistant storage folder:
|
||||
file.directory:
|
||||
- name: /srv/rancher-container
|
||||
- user: root
|
||||
- group: root
|
||||
- mode: "0640"
|
||||
- replace: False
|
||||
|
||||
Stop rancher container before rebuild:
|
||||
service.dead:
|
||||
- name: rancher
|
||||
- onchanges:
|
||||
- cmd: Pull rancher image
|
||||
|
||||
Remove old rancher container:
|
||||
cmd.run:
|
||||
- name: podman container rm rancher
|
||||
- onlyif: podman container exists rancher
|
||||
- onchanges:
|
||||
- cmd: Pull rancher image
|
||||
|
||||
Create rancher container:
|
||||
cmd.run:
|
||||
- name: podman container create --name rancher --privileged --publish 9080:80 --publish 9443:443 --volume /etc/rancher/ssl/rancher-server.crt:/etc/rancher/ssl/cert.pem --volume /etc/rancher/ssl/rancher-server.key:/etc/rancher/ssl/key.pem --volume /etc/rancher/ssl/rancher-ca.crt:/etc/rancher/ssl/cacerts.pem --volume /srv/rancher-container:/var/lib/rancher --env CATTLE_BOOTSTRAP_PASSWORD={{ pillar['rancher']['bootstrapPassword'] }} {{ pillar['rancher']['url'] }}:{{ pillar['rancher']['tag'] }}
|
||||
- unless: podman container exists rancher
|
||||
|
||||
Start the rancher container:
|
||||
service.running:
|
||||
- name: rancher
|
||||
- enable: True
|
||||
- watch:
|
||||
- file: Create rancher systemd unit file
|
||||
|
@ -7,10 +7,10 @@ start sshd:
|
||||
- name: sshd
|
||||
- enable: True
|
||||
|
||||
{% if pillar['ssh']['user-pub-keys'] %}
|
||||
{% if pillar['ssh']['user_pub_keys'] %}
|
||||
{{ pillar['username'] }}_autherized_keys:
|
||||
ssh_auth:
|
||||
- present
|
||||
- user: {{ pillar['username'] }}
|
||||
- names: {{ pillar['ssh']['user-pub-keys'] }}
|
||||
- names: {{ pillar['ssh']['user_pub_keys'] }}
|
||||
{% endif %}
|
||||
|
@ -14,9 +14,9 @@ base:
|
||||
- rmt
|
||||
- podman
|
||||
- docker.registry
|
||||
- rancher
|
||||
- remote-desktop
|
||||
- wol
|
||||
- pxe
|
||||
- tlu-harvester
|
||||
- nfs-server
|
||||
- kvm
|
||||
|
148
update.sh
148
update.sh
@ -13,6 +13,7 @@ Usage ${0##*/} [options..]
|
||||
-s, --salt run a masterless salt-call
|
||||
-y, --yes answer 'yes' on all questions
|
||||
-t, --tools Install/update tools (kubectl, helm, etc)
|
||||
-r, --rancher Install rancher server VM
|
||||
--rmt-sync Sync database with SUSE Customer Center
|
||||
--rmt-enable-products Enable all preconfigured repositories
|
||||
--rmt-mirror Mirror repositories
|
||||
@ -113,9 +114,9 @@ function rmt_sync(){
|
||||
|
||||
function rmt_enable_products(){
|
||||
new_log "Enable the following products in RMT?"
|
||||
eval $(parse_yaml salt/pillars/rmt.sls "SALT_")
|
||||
eval $(parse_yaml $SCRIPTDIR/salt/pillars/rmt.sls "SALT_")
|
||||
if [[ -f salt/pillars/local.sls ]];then
|
||||
eval $(parse_yaml salt/pillars/local.sls "SALT_")
|
||||
eval $(parse_yaml $SCRIPTDIR/salt/pillars/local.sls "SALT_")
|
||||
fi
|
||||
for name in "${SALT_rmt_products__name[@]}"; do
|
||||
echo " * $name"
|
||||
@ -219,6 +220,143 @@ function install_tools(){
|
||||
set -e
|
||||
}
|
||||
|
||||
function install_rancher_vm(){
|
||||
new_log "Install rancher vm"
|
||||
if asktobreak; then
|
||||
return
|
||||
fi
|
||||
systemctl is-active libvirtd --quiet || ( echo "libvirtd is not running...."; return 1)
|
||||
if sudo virsh list --all | grep -q "rancher";then
|
||||
echo "rancher VM already installed..."
|
||||
return 0
|
||||
fi
|
||||
eval $(parse_yaml $SCRIPTDIR/salt/pillars/network.sls "SALT_")
|
||||
eval $(parse_yaml $SCRIPTDIR/salt/pillars/rancher.sls "SALT_")
|
||||
eval $(parse_yaml $SCRIPTDIR/salt/pillars/ssh.sls "SALT_")
|
||||
eval $(parse_yaml $SCRIPTDIR/salt/pillars/local.sls "SALT_")
|
||||
# Download openSUSE MicroOS image
|
||||
if sudo test ! -f /var/lib/libvirt/images/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2;then
|
||||
echo "Downloading MicroOS"
|
||||
curl -Lo /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2 http://download.opensuse.org/tumbleweed/appliances/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2
|
||||
curl -Lo /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2.sha256 http://download.opensuse.org/tumbleweed/appliances/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2.sha256
|
||||
cd /tmp/
|
||||
echo "checking sha256sum"
|
||||
if ! echo "$(cat /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2.sha256 | cut -f 1 -d " ") openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2" | sudo sha256sum --check --status;then
|
||||
echo "sha256sum doesn't match on openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2"
|
||||
exit 1
|
||||
fi
|
||||
echo "Moving image file to /var/lib/libvirt/images"
|
||||
sudo mv /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2 /var/lib/libvirt/images/
|
||||
fi
|
||||
|
||||
# Create the Butane config file
|
||||
if [[ -f $HOME/rancherVM.yaml ]]; then
|
||||
echo "rancher butane file already exists"
|
||||
else
|
||||
SSH_PUB_KEYS=""
|
||||
for i in "${SALT_ssh_user_pub_keys[@]}"; do
|
||||
if [[ "$i" != "[]" ]];then
|
||||
SSH_PUB_KEYS="$SSH_PUB_KEYS - $i\n"
|
||||
fi
|
||||
done
|
||||
cat << EOF >> $HOME/rancherVM.yaml
|
||||
variant: fcos
|
||||
version: 1.0.0
|
||||
passwd:
|
||||
users:
|
||||
- name: root
|
||||
ssh_authorized_keys:
|
||||
$(echo -e "$SSH_PUB_KEYS")
|
||||
password_hash: "$(echo ${SALT_rancher_bootstrapPassword} | mkpasswd --method=SHA-512 --stdin)"
|
||||
storage:
|
||||
files:
|
||||
- path: /etc/sysconfig/network/ifcfg-eth0
|
||||
mode: 0600
|
||||
overwrite: true
|
||||
contents:
|
||||
inline: |
|
||||
BOOTPROTO='static'
|
||||
STARTMODE='auto'
|
||||
BROADCAST=''
|
||||
ETHTOOL_OPTIONS=''
|
||||
IPADDR='${SALT_network_ip%.*}.${SALT_network_hosts_rancher}/24'
|
||||
MTU=''
|
||||
NAME=''
|
||||
NETWORK=''
|
||||
REMOTE_IPADDR=''
|
||||
ZONE=internal
|
||||
- path: /etc/sysconfig/network/routes
|
||||
mode: 0644
|
||||
overwrite: true
|
||||
contents:
|
||||
inline: |
|
||||
default ${SALT_network_ip} - -
|
||||
- path: /etc/rancher/k3s/registries.yaml
|
||||
mode: 0600
|
||||
contents:
|
||||
inline: |
|
||||
mirrors:
|
||||
docker.io:
|
||||
endpoint:
|
||||
- "http://${SALT_network_ip}:5000"
|
||||
- path: /etc/hostname
|
||||
mode: 0644
|
||||
overwrite: true
|
||||
contents:
|
||||
inline: |
|
||||
rancher.${SALT_network_domain}
|
||||
EOF
|
||||
|
||||
# Create the ignition file
|
||||
fi
|
||||
if [[ -f $HOME/rancherVM.ign ]];then
|
||||
echo "rancher ignition file already exists"
|
||||
else
|
||||
sudo podman run -i --rm quay.io/coreos/fcct:release --pretty --strict < $HOME/rancherVM.yaml > $HOME/rancherVM.ign
|
||||
fi
|
||||
|
||||
#create the rancher VM
|
||||
sudo virt-install --import --connect qemu:///system \
|
||||
--name rancher \
|
||||
--ram "${SALT_rancher_ram}" \
|
||||
--vcpus "$SALT_rancher_vcpus" \
|
||||
--disk size=20,backing_store=/var/lib/libvirt/images/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2,bus=virtio \
|
||||
--os-variant=opensusetumbleweed \
|
||||
--network bridge=br0,model=virtio,mac=E8:01:F0:52:2E:E2\
|
||||
--noautoconsole \
|
||||
--graphics spice,listen=127.0.0.1 \
|
||||
--qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=$HOME/rancherVM.ign"
|
||||
|
||||
printf "%s" "Waiting for rancher VM ssh to come up"
|
||||
while ! nc -z rancher."${SALT_network_domain}" 22 &> /dev/null; do
|
||||
printf "%c" "."
|
||||
sleep 1
|
||||
done
|
||||
printf "\nAdding rancher VM into ssh known_hosts\n"
|
||||
ssh-keyscan -H "rancher.${SALT_network_domain}" >> $HOME/.ssh/known_hosts
|
||||
ssh-keyscan -H "${SALT_network_ip%.*}.${SALT_network_hosts_rancher}" >> $HOME/.ssh/known_hosts
|
||||
echo "Setting DNS server"
|
||||
ssh root@rancher."${SALT_network_domain}" sed -i "s/^NETCONFIG_DNS_STATIC_SERVERS=\"\"/NETCONFIG_DNS_STATIC_SERVERS=\"${SALT_network_ip}\"/" /etc/sysconfig/network/config
|
||||
|
||||
#TODO: need to reboot guest for some reason, stop answering to ping in this stage
|
||||
#TODO: need to investigate why
|
||||
echo "Reboot rancher VM"
|
||||
sudo virsh destroy rancher
|
||||
sleep 5
|
||||
sudo virsh start rancher
|
||||
printf "%s" "Waiting for rancher VM ssh to come up"
|
||||
while ! nc -z rancher."${SALT_network_domain}" 22 &> /dev/null; do
|
||||
printf "%c" "."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Installing k3s"
|
||||
ssh root@rancher."${SALT_network_domain}" 'bash -c "curl -sfL https://get.k3s.io | sh -"'
|
||||
echo "Waiting for k3s to be healthy"
|
||||
ssh root@rancher."${SALT_network_domain}" 'bash -c "while ! kubectl get cs &> /dev/null;do sleep 1; done"'
|
||||
|
||||
|
||||
}
|
||||
|
||||
#########################
|
||||
#
|
||||
@ -234,6 +372,7 @@ RMT_SYNC=false
|
||||
RMT_MIRROR=false
|
||||
RMT_ENABLE_PRODUCTS=false
|
||||
INSTALL_TOOLS=false
|
||||
RANCHER=false
|
||||
|
||||
while :; do
|
||||
case ${1-noop} in
|
||||
@ -248,6 +387,10 @@ while :; do
|
||||
-y|--yes)
|
||||
ANSWER_YES=true
|
||||
;;
|
||||
-r|--rancher)
|
||||
RANCHER=true
|
||||
ALL=false
|
||||
;;
|
||||
--rmt-sync)
|
||||
RMT_SYNC=true
|
||||
ALL=false
|
||||
@ -287,6 +430,7 @@ done
|
||||
[[ $ALL == true ]] || [[ $RMT_ENABLE_PRODUCTS == true ]] && rmt_enable_products
|
||||
[[ $ALL == true ]] || [[ $RMT_MIRROR == true ]] && rmt_mirror
|
||||
[[ $ALL == true ]] || [[ $INSTALL_TOOLS == true ]] && install_tools
|
||||
[[ $ALL == true ]] || [[ $RANCHER == true ]] && install_rancher_vm
|
||||
|
||||
|
||||
printf "\n DONE!!!!!!!\n"
|
||||
|
Loading…
Reference in New Issue
Block a user