Reusing apache-server instead of httpd

Since we already introduced apache server for redfish,
it will be a good idea to use it for sharing iso also.
These changes add file-exchanger config that can be
used to share iso. In addition apache allows the
specified users (see rbac config) to upload files.
This may help in future to better emulate deployment
environment, where it will be necessary to do this
step after airshipctl generated iso and before
airshipctl invokes redfish to run that iso.

Change-Id: Ice47fe977fb71cf9df14d39c5ac26e365e2006f2
This commit is contained in:
Alexey Odinokov 2020-04-17 04:00:50 +00:00
parent a37a8800cc
commit 16d2c8d8c1
30 changed files with 453 additions and 169 deletions

View File

@ -23,6 +23,14 @@
include_role:
name: docker-install
- name: make sure serve directory exists
file:
dest: "{{ serve_dir }}"
state: directory
mode: "0755"
owner: "{{ ansible_user }}"
become: true
- name: deploy-gate
include_role:
name: airship-libvirt-gate
@ -44,20 +52,26 @@
target_disk_size: 10G
disk_format: qcow2
target_vms_count: 1
- name: make sure serve directory exists
file:
dest: "{{ serve_dir }}"
state: directory
mode: "0755"
owner: "{{ ansible_user }}"
become: true
- name: serve iso directory
include_role:
name: http-fileserver
vars:
http_fileserver_serve_dir: "{{ serve_dir }}"
http_fileserver_serve_port: "{{ serve_port }}"
airship_gate_file_exchanger:
servername: "loacalhost"
ip:
- "127.0.0.1"
- "::1"
http_port: "{{ serve_port }}"
path: "{{ serve_dir }}"
user:
- username: "username"
password: "password"
group:
- name: writers
member:
- username
rbac:
policies:
- role:
- PUT
group:
- writers
default:
all: granted

View File

@ -47,6 +47,25 @@ airship_gate_redfish_auth:
- username: "username"
password: "password"
airship_gate_file_exchanger:
servername: "loacalhost"
ip:
- "127.0.0.1"
- "::1"
http_port: 8100
path: "/srv"
user:
- username: "username"
password: "password"
rbac:
policies:
- role:
- PUT
user:
- username
default:
all: granted
airship_gate_flavors:
small:
target_vm_memory_mb: 1024

View File

@ -125,4 +125,15 @@
sushy_emulator_frontend_https_port: "{{ airship_gate_redfish_auth.https_port }}"
sushy_emulator_frontend_user: "{{ airship_gate_redfish_auth.user }}"
- name: Add file-exchanger to apache
include_role:
name: apache-file-exchanger
vars:
file_exchanger_name: airship_gate_file_exchanger
file_exchanger_http_port: "{{ airship_gate_file_exchanger.http_port | default(0) }}"
file_exchanger_https_port: "{{ airship_gate_file_exchanger.https_port | default(0) }}"
file_exchanger_path: "{{ airship_gate_file_exchanger.path }}"
file_exchanger_user: "{{ airship_gate_file_exchanger.user | default(None)}}"
file_exchanger_group: "{{ airship_gate_file_exchanger.group | default(None) }}"
file_exchanger_rbac: "{{ airship_gate_file_exchanger.rbac | default(None) }}"

View File

@ -10,14 +10,36 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- name: reload systemd configuration
become: yes
systemd:
daemon_reload: yes
file_exchanger_name: iso_file_exchanger
file_exchanger_servername: localhost
file_exchanger_ip:
- "127.0.0.1"
- "::1"
file_exchanger_http_port: 8100
- name: http file server restarted
service:
name: simple-http-{{ http_fileserver_name | default('default') }}.service
state: restarted
enabled: true
become: true
file_exchanger_path: /var/www/iso_file_exchanger/
file_exchanger_user:
- username: user1
password: password
- username: user2
password: password
file_exchanger_group:
- name: ReadOnly
member:
- user1
- user2
- name: ReadWrite
member:
- user2
file_exchanger_rbac:
policies:
- role:
- PUT
group:
- ReadWrite
default:
group:
- ReadOnly

View File

@ -0,0 +1,118 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
- name: ensure OS
when: ansible_distribution != 'Debian' and ansible_distribution != 'Ubuntu'
fail:
msg: "Only Debian|Ubuntu are currently supported"
- name: Confguring file-exchanger
become: true
block:
- name: Ensure backend
file:
path: /var/www/file_exchanger_cgi-bin/
state: directory
- name: Created put cgi-bin file
template:
src: put
dest: /var/www/file_exchanger_cgi-bin/put
mode: +x
- name: Ensure path exists
file:
path: "{{ file_exchanger_path }}"
state: directory
owner: www-data
group: root
mode: u+rwx,g-w,o-w
- name: Enable related modules
apache2_module:
name: "{{ item }}"
state: present
with_items:
- authz_groupfile
- actions
- alias
- cgid
- name: Create httpasswd file
when: file_exchanger_user is defined and file_exchanger_user != None
include_role:
name: apache-server
vars:
apache_server_action: htpasswd
apache_server_htpasswd_path: "/etc/apache2/sites-available/{{ file_exchanger_name }}.htpasswd"
apache_server_htpasswd_user: "{{ file_exchanger_user }}"
- name: Create htaccess file
when: file_exchanger_group is defined and file_exchanger_group != None
include_role:
name: apache-server
vars:
apache_server_action: htaccess
apache_server_htaccess_path: "/etc/apache2/sites-available/{{ file_exchanger_name }}.htaccess"
apache_server_htaccess_group: "{{ file_exchanger_group }}"
- name: Create file-exchanger HTTP virtual host config
when: file_exchanger_http_port is defined and file_exchanger_http_port != "0"
block:
- name: Create file-exchanger virtual host config for HTTP
template:
src: conf.j2
dest: "/etc/apache2/sites-available/{{ file_exchanger_name }}.conf"
- name: Enable file-exchanger virtual host
command: "a2ensite {{ file_exchanger_name }}"
- name: Create file-exchanger HTTPS virtual host config
when: file_exchanger_https_port is defined and file_exchanger_https_port != "0"
block:
- name: Generate certs for casewith alt_names
when: file_exchanger_ip is defined and file_exchanger_ip != None
include_role:
name: apache-server
vars:
apache_server_action: ssl
apache_server_ssl_key_path: "/etc/ssl/private/{{ file_exchanger_name }}.key"
apache_server_ssl_cert_path: "/etc/ssl/certs/{{ file_exchanger_name }}.pem"
apache_server_ssl_cn: "{{ file_exchanger_servername }}"
apache_server_ssl_alt_name: "{{ file_exchanger_ip | map('regex_replace', '(.*)', 'IP:\\1') | list }}"
- name: Generate certs for case without alt_names
when: file_exchanger_ip is undefined or file_exchanger_ip == None
include_role:
name: apache-server
vars:
apache_server_action: ssl
apache_server_ssl_key_path: "/etc/ssl/private/{{ file_exchanger_name }}.key"
apache_server_ssl_cert_path: "/etc/ssl/certs/{{ file_exchanger_name }}.pem"
apache_server_ssl_cn: "{{ file_exchanger_servername }}"
- name: Create file-exchanger virtual host config for HTTPS
template:
src: ssl.conf.j2
dest: "/etc/apache2/sites-available/{{ file_exchanger_name }}-ssl.conf"
- name: Enable file-exchanger virtual host
command: "a2ensite {{ file_exchanger_name }}-ssl"
- name: Restart Apache to apply all changes
include_role:
name: apache-server
vars:
apache_server_action: restart

View File

@ -0,0 +1,53 @@
{% from 'macroses.j2' import render_rbac as _render_rbac %}
{% if file_exchanger_http_port != 80 %}
Listen {{ file_exchanger_http_port }}
{% endif %}
<VirtualHost {{ file_exchanger_ip | default(['*']) | ipwrap | map('regex_replace', '(.*)', '\\1:{}'.format(file_exchanger_http_port)) | list | join(' ') }}>
# Add machine's IP address (use ifconfig command)
ServerName {{ file_exchanger_servername }}
{% if file_exchanger_user is defined and file_exchanger_user != None %}
<Directory /var/www/file_exchanger_cgi-bin/>
AuthType Basic
AuthName "Authorised cgi-bin"
AuthUserFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htpasswd
{% if file_exchanger_group is defined and file_exchanger_group != None %}
AuthGroupFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htaccess
{% endif %}
{% if file_exchanger_rbac is defined and file_exchanger_rbac != None %}
{{ _render_rbac(file_exchanger_rbac) }}
{% else %}
Require valid-user
{% endif %}
</Directory>
ScriptAlias /cgi-bin /var/www/file_exchanger_cgi-bin/
{% endif %}
# Give an alias to to start your website url with
DocumentRoot "{{ file_exchanger_path }}"
<Location />
Options Indexes FollowSymLinks
AllowOverride None
{% if file_exchanger_user is defined and file_exchanger_user != None %}
AuthType Basic
AuthName "Authentication Required"
AuthUserFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htpasswd
{% if file_exchanger_group is defined and file_exchanger_group != None %}
AuthGroupFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htaccess
{% endif %}
{% if file_exchanger_rbac is defined and file_exchanger_rbac != None %}
{{ _render_rbac(file_exchanger_rbac) }}
{% else %}
Require valid-user
{% endif %}
Script PUT /cgi-bin/put
{% else %}
Require all granted
{% endif %}
</Location>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

View File

@ -0,0 +1,29 @@
{% macro render_require(item) -%}
{% if item == "valid_user" %}
Require valid-user
{% elif item.group is defined %}
Require group {{ item.group | join(' ') }}
{% elif item.user is defined %}
Require user {{ item.user | join(' ') }}
{% elif item.all is defined %}
Require all {{ item.all }}
{% else %}
Require all denied
{% endif %}
{%- endmacro %}
{% macro render_rbac(rbac) -%}
{# rbac #}
{% if rbac is defined and rbac.policies is defined %}
{% for item in rbac.policies %}
<Limit {{ item.role | join(' ') }}>
{{ render_require(item) }}
</Limit>
{% endfor %}
<LimitExcept{% for item in rbac.policies %} {{ item.role | join(' ') }}{% endfor %}>
{{ render_require(rbac.default) }}
</LimitExcept>
{% else %}
{{ render_require(rbac.default) }}
{% endif %}
{%- endmacro %}

View File

@ -0,0 +1,88 @@
#!/usr/bin/env perl
# http://www.apacheweek.com/features/put with enabling syslog
# Very simple PUT handler. Read the Apache Week article before attempting
# to use this script. You are responsible for ensure that this script is
# used securely.
# A simple log file, must be writable by the user that this program runs as.
# Should not be within the document tree.
use Sys::Syslog;
# Check we are using PUT method
if ($ENV{'REQUEST_METHOD'} ne "PUT") { &reply(500, "Request method is not PUT"); }
# Note: should also check we are an authentication user by checking
# REMOTE_USER
# Check we got a destination filename
$filename = $ENV{'PATH_TRANSLATED'};
if (!$filename) { &reply(500, "No PATH_TRANSLATED"); }
# Check we got some content
$clength = $ENV{'CONTENT_LENGTH'};
if (!$clength) { &reply(500, "Content-Length missing or zero ($clength)"); }
# Read the content itself
$toread = $clength;
$content = "";
while ($toread > 0)
{
$nread = read(STDIN, $data, $clength);
&reply(500, "Error reading content") if !defined($nread);
$toread -= $nread;
$content = $data;
}
# Write it out
# Note: doesn't check the location of the file, whether it already
# exists, whether it is a special file, directory or link. Does not
# set the access permissions. Does not handle subdirectories that
# need creating.
open(OUT, "> $filename") || &reply(500, "Cannot write to $filename");
print OUT $content;
close(OUT);
# Everything seemed to work, reply with 204 (or 200). Should reply with 201
# if content was created, not updated.
&reply(204);
exit(0);
#
# Send back reply to client for a given status.
#
sub reply
{
local($status, $message) = @_;
local($remuser, $remhost, $logline) = ();
print "Status: $status\n";
print "Content-Type: text/html\n\n";
if ($status == 200) {
print "<HEAD><TITLE>OK</TITLE></HEAD><H1>Content Accepted</H1>\n";
} elsif ($status == 500) {
print "<HEAD><TITLE>Error</TITLE></HEAD><H1>Error Publishing File</H1>\n";
print "An error occurred publishing this file ($message).\n";
}
# Note: status 204 and 201 gives have content part
# Create a simple log
$remuser = $ENV{'REMOTE_USER'} || "-";
$remhost = $ENV{'REMOTE_HOST'} || $ENV{'REMOTE_ADDR'} || "-";
$logline = "$remhost $remuser $filename status $status";
$logline .= " ($message)" if ($status == 500);
&log($logline);
exit(0);
}
sub log
{
local($msg) = @_;
openlog("", "ndelay,pid", "local0");
syslog("info", $msg);
closelog();
}

View File

@ -0,0 +1,53 @@
{% from 'macroses.j2' import render_rbac as render_rbac %}
<IfModule mod_ssl.c>
{% if file_exchanger_https_port != 443 %}
Listen {{ file_exchanger_https_port }}
{% endif %}
<VirtualHost {{ file_exchanger_ip | default(['*']) | ipwrap | map('regex_replace', '(.*)', '\\1:{}'.format(file_exchanger_https_port)) | list | join(' ') }}>
# Add machine's IP address (use ifconfig command)
{% if file_exchanger_user is defined and file_exchanger_user != None %}
<Directory /var/www/file_exchanger_cgi-bin/>
AuthType Basic
AuthName "Authorised cgi-bin"
AuthUserFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htpasswd
{% if file_exchanger_group is defined and file_exchanger_group != None %}
AuthGroupFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htaccess
{% endif %}
{% if file_exchanger_rbac is defined and file_exchanger_rbac != None %}
{{ render_rbac(file_exchanger_rbac) }}
{% else %}
Require valid-user
{% endif %}
</Directory>
ScriptAlias /cgi-bin /var/www/file_exchanger_cgi-bin/
{% endif %}
# Give an alias to to start your website url with
DocumentRoot "{{ file_exchanger_path }}"
<Location />
Options Indexes FollowSymLinks
AllowOverride None
{% if file_exchanger_user is defined and file_exchanger_user != None %}
AuthType Basic
AuthName "Authentication Required"
AuthUserFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htpasswd
{% if file_exchanger_group is defined and file_exchanger_group != None %}
AuthGroupFile /etc/apache2/sites-available/{{ file_exchanger_name }}.htaccess
{% endif %}
{% if file_exchanger_rbac is defined and file_exchanger_rbac != None %}
{{ render_rbac(file_exchanger_rbac) }}
{% else %}
Require valid-user
{% endif %}
Script PUT /cgi-bin/put
{% else %}
Require all granted
{% endif %}
</Location>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
</IfModule>

View File

@ -18,6 +18,12 @@ apache_server_htpasswd_user:
- username: username
password: password
apache_server_htaccess_path: /etc/apache2/sites-available/.htaccess
apache_server_htaccess_group:
- name: ReadOnly
member:
- username
apache_server_ssl_cn: localhost
apache_server_ssl_alt_name:
- "IP:127.0.0.1"

View File

@ -10,6 +10,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
http_fileserver_serve_dir: /srv/http-server
http_fileserver_serve_port: 8099
http_server_action: install
- name: Generate htaccess file
become: true
template:
src: htaccess.j2
dest: "{{ apache_server_htaccess_path }}"

View File

@ -10,4 +10,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- include_tasks: "{{ http_server_action }}.yaml"
- include_tasks: "{{ apache_server_action }}.yaml"

View File

@ -37,7 +37,7 @@
common_name: "{{ apache_server_ssl_cn }}"
subject_alt_name: "{{ apache_server_ssl_alt_name }}"
- name: Generate the self signed certificate for sushy-emulator
- name: Generate the self signed certificate
openssl_certificate:
path: "{{ apache_server_ssl_cert_path }}"
privatekey_path: "{{ apache_server_ssl_key_path }}"

View File

@ -0,0 +1,3 @@
{% for item in apache_server_htaccess_group %}
{{ "{}: {}".format(item.name, item.member | join(' ')) }}
{% endfor %}

View File

@ -10,4 +10,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- include_tasks: "{{ apache_server_action }}.yml"
- include_tasks: "{{ sushy_emulator_action }}.yaml"

View File

@ -1,13 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
- include_tasks: "{{ sushy_emulator_action }}.yml"

View File

@ -2,7 +2,7 @@
{% if sushy_emulator_frontend_https_port != 443 %}
Listen {{ sushy_emulator_frontend_https_port }}
{% endif %}
<VirtualHost *:{{ sushy_emulator_frontend_https_port }}>
<VirtualHost {{ sushy_emulator_frontend_ip | default(['*']) | ipwrap | map('regex_replace', '(.*)', '\\1:{}'.format(sushy_emulator_frontend_https_port)) | list | join(' ') }}>
# Add machine's IP address (use ifconfig command)
ServerName {{ sushy_emulator_frontend_servername }}
# Give an alias to to start your website url with

View File

@ -1,7 +1,7 @@
{% if sushy_emulator_frontend_http_port != 80 %}
Listen {{ sushy_emulator_frontend_http_port }}
{% endif %}
<VirtualHost *:{{ sushy_emulator_frontend_http_port }}>
<VirtualHost {{ sushy_emulator_frontend_ip | default(['*']) | ipwrap | map('regex_replace', '(.*)', '\\1:{}'.format(sushy_emulator_frontend_http_port)) | list | join(' ') }}>
# Add machine's IP address (use ifconfig command)
ServerName {{ sushy_emulator_frontend_servername }}
# Give an alias to to start your website url with

View File

@ -1,45 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
- name: install simplehttpserver package
apt:
name:
- python3
state: present
become: true
- name: set http server systemd unit content
set_fact:
http_fileserver_unit_content: |
[Unit]
Description=Simple http server
After=syslog.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 -m http.server {{ http_fileserver_serve_port }}
StandardOutput=syslog
StandardError=syslog
WorkingDirectory={{ http_fileserver_serve_dir }}
[Install]
WantedBy=multi-user.target
- name: Create systemd unit
copy:
content: "{{ http_fileserver_unit_content }}"
dest: /etc/systemd/system/simple-http-{{ http_fileserver_name | default('default') }}.service
notify:
- reload systemd configuration
- http file server restarted
become: true

View File

@ -1,18 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
- name: ensure http service is stopped
service:
name: simple-http-{{ http_fileserver_name | default('default') }}.service
state: stopped
enabled: false
become: true

View File

@ -1,42 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
- name: Include test variables.
include_vars:
file: vars.yaml
- name: ensure serve directory exists
file:
path: "{{ http_fileserver_serve_dir }}"
state: directory
mode: "0755"
become: true
- name: install http-fileserver
include_role:
name: http-fileserver
- name: trigger all saved handlers
meta: flush_handlers
- name: copy test file to serve directory
become: true
copy:
content: "{{ http_file_server_test_file_content }}"
dest: "{{ http_fileserver_serve_dir }}/{{ http_fileserver_test_file_name }}"
register: file_copy_command
- name: download test file
get_url:
url: "http://localhost:{{ http_fileserver_serve_port }}/{{ http_fileserver_test_file_name }}"
dest: "/tmp/{{ http_fileserver_test_file_name }}"
checksum: "sha1:{{ file_copy_command.checksum }}"

View File

@ -1,16 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
http_fileserver_serve_dir: /srv/test-dir
http_fileserver_serve_port: 8095
http_file_server_test_file_content: "something to test"
http_fileserver_test_file_name: "test-file"

View File

@ -22,7 +22,6 @@
- libvirt-domain
- apache-wsgi-sushy-emulator
- airship-libvirt-gate
- http-fileserver
- name: run tests against defined roles
include_tasks: "../../roles/{{ role_name }}/tests/main.yaml"
with_items: "{{ test_subject_roles | default(test_subject_roles_default) }}"