#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#
from . import testutils
if __name__ == "__main__":
import pkg5unittest
import copy
import os
import six
import time
import unittest
import certgenerator
import shutil
# An array that can be used to build our svcs(1) wrapper.
# FMRI STATE
["svc:/application/pkg/server:default", "online" ],
["svc:/application/pkg/server:usr", "online" ],
# an instance which we have a writable_root for
["svc:/application/pkg/server:windex", "online" ],
# repositories that we will not serve
["svc:/application/pkg/server:off", "offline"],
["svc:/application/pkg/server:writable", "online" ],
["svc:/application/pkg/server:solitary", "offline"]
]
# An array that can be used to build our svcprop(1)
# wrapper in conjunction with svcs_conf. This array
# must be in the same order as svcs_conf and the rows
# must correspond.
# inst_root readonly standalone writable_root
["{rdir1}", "true", "false", "\"\""],
["{rdir2}", "true", "false", "\"\""],
["{rdir3}", "true", "false", "{index_dir}"],
# we intentionally use non-existent repository
# paths in these services, and check they aren't
# present in the httpd.conf later.
]
sample_pkg = """
open sample@1.0,5.11-0
close"""
sample_pkg_11 = """
open sample@1.1,5.11-0
close"""
new_pkg = """
open new@1.0,5.11-0
close"""
another_pkg = """
open another@1.0,5.11-0
close"""
carrots_pkg = """
close"""
_svcs_template = \
#
# This script produces false svcs(1) output, using
# a list of space separated strings, with each string
# of the format <fmri>%<state>
#
# eg.
# SERVICE_STATUS="svc:/application/pkg/server:foo%online svc:/application/pkg/server:default%offline svc:/application/pkg/server:usr%online"
# We expect to be called with 'svcs -H -o fmri <fmri>' but completely ignore
# the <fmri> argument.
#
SERVICE_STATUS="{0}"
set -- `getopt o:H $*`
for i in $* ; do
case $i in
-H) minus_h=$i; shift;;
-o) minus_o=$2; shift;;
*) break;;
esac
done
if [ "${{minus_o}}" ]; then
if [ -z "${{minus_h}}" ]; then
echo "FMRI"
fi
for service in $SERVICE_STATUS ; do
echo $service | sed -e 's/%/ /' | read fmri state
echo $fmri
done
exit 0
fi
if [ -z "${{minus_h}}" ]; then
printf "%-14s%6s %s\n" STATE STIME FMRI
fi
for service in $SERVICE_STATUS ; do
echo $service | sed -e 's/%/ /' | read fmri state
printf "%-14s%9s %s\n" $state 00:00:00 $fmri
done
"""
#
# This script produces false svcprop(1) output, using
# a list of space separated strings, with each string
# of the format <fmri>%<state>%<inst_root>%<readonly>%<standalone>%<writable_root>
#
# eg.
# SERVICE_PROPS="svc:/application/pkg/server:foo%online%/space/repo%true%false%/space/writable_root"
#
# we expect to be called as "svcprop -c -p <property> <fmri>"
# which is enough svcprop(1) functionalty for these tests. Any other
# command line options will cause us to return nonsense.
#
typeset -A prop_state
typeset -A prop_readonly
typeset -A prop_inst_root
typeset -A prop_standalone
typeset -A prop_writable_root
SERVICE_PROPS="{0}"
for service in $SERVICE_PROPS ; do
echo $service | sed -e 's/%/ /g' | \
read fmri state inst_root readonly standalone writable_root
# create a hashable version of the FMRI
fmri=$(echo $fmri | sed -e 's/\///g' -e 's/://g')
prop_state[$fmri]=$state
prop_inst_root[$fmri]=$inst_root
prop_readonly[$fmri]=$readonly
prop_standalone[$fmri]=$standalone
prop_writable_root[$fmri]=$writable_root
done
FMRI=$(echo $4 | sed -e 's/\///g' -e 's/://g')
case $3 in
echo ${{prop_inst_root[$FMRI]}}
;;
echo ${{prop_readonly[$FMRI]}}
;;
"pkg/standalone")
echo ${{prop_standalone[$FMRI]}}
;;
"pkg/writable_root")
echo ${{prop_writable_root[$FMRI]}}
;;
echo ${{prop_state[$FMRI]}}
;;
*)
echo "Completely bogus svcprop output. Sorry."
esac
"""
# A very minimal httpd.conf, which contains an Include directive
# that we will use to reference our pkg5 depot-config.conf file. We leave
# an Alias pointing to /server-status to make this server distinctive
# for this test case.
PidFile "{runtime_dir}/default_httpd.pid"
Listen {port}
LoadModule access_compat_module libexec/mod_access_compat.so
LoadModule alias_module libexec/mod_alias.so
LoadModule authz_core_module libexec/mod_authz_core.so
LoadModule dir_module libexec/mod_dir.so
LoadModule headers_module libexec/mod_headers.so
LoadModule log_config_module libexec/mod_log_config.so
LoadModule mpm_worker_module libexec/mod_mpm_worker.so
LoadModule rewrite_module libexec/mod_rewrite.so
LoadModule ssl_module libexec/mod_ssl.so
LoadModule status_module libexec/mod_status.so
LoadModule unixd_module libexec/mod_unixd.so
User webservd
Group webservd
ServerAdmin you@yourhost.com
ServerName 127.0.0.1
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
LogFormat \"%h %l %u %t \\\"%r\\\" %>s %b\" common
ErrorLog "{runtime_dir}/error_log"
CustomLog "{runtime_dir}/access_log" common
LogLevel debug
# Reference the depot.conf file generated by pkg.depot-config, which makes this
# web server into something that can serve pkg(7) repositories.
Include {depot_conf}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
# We enable server-status here, using /pkg5test-server-status to it to make the
# URI distinctive.
<Location /pkg5test-server-status>
SetHandler server-status
</Location>
"""
"test2", "test3"])
"depot_writable_root")
"depot_runtime")
"""Create wrapper scripts for svcprop and svcs based on the
arrays of arrays passed in as arguments. By default, the
following responses are configured using the class variables
svcs_conf and svcprop_conf:
depot-config as they are marked readonly=true, standalone=false.
offline for these tests.
eligible to be served by the depot, the former, because it
is not marked as readonly, the latter because it is marked
as standalone.
"""
# we don't want to modify our arguments
# ensure the arrays are the same length.
# construct two strings we can use as parameters to our
# __svc*_template values
for item in _svcs_conf])
for item in _svcprop_conf])
}
if build_indexes:
# we won't return until indexes are built
u = urlopen(
"""Tests that exercise the pkg.depot-config CLI as well as checking the
functionality of the depot-config itself for configuring http service.
This test class will fail if not run as root, since many of the tests
use 'pkg.depot-config -a' which will attempt to chown a directory to
pkg5srv:pkg5srv.
The default_svcs_conf having an instance name of 'usr' is not a
coincidence: we use it there so that we catch RewriteRules that
mistakenly try to serve content from the root filesystem ('/') rather
than from beneath our DocumentRoot (assuming that test systems always
have a /usr directory)
"""
"""A basic test to see that we can start the depot,
as part of this, by starting the depot, ApacheController will
ping the "/ URI of the server."""
# ensure we fail when not supplying the required argument
# the httpd.conf should reference our repositories
# it should not reference the repositories that we have
# marked as offline, writable or standalone
"""Tests that we show a usage message."""
"""We return an error given an invalid image root"""
# check for incorrectly-formed -d options
# ensure we pick up invalid -d directories
for invalid_root in ["usr=/dev/null",
exit=1)
"error message did not contain {0}: {1}".format(
# ensure we also catch invalid SMF inst_roots
exit=1)
"/tmp")
# ensure we pick up invalid writable_root directories
# but check that we allow valid writeable_roots
"""We return an error given an invalid cache_dir"""
"""We return an error given an invalid hostname"""
"""We return an error given an invalid logs_dir"""
for invalid_log in ["/proc"]:
exit=0)
"""We return an error given an invalid port"""
"""We return an error given an invalid runtime_dir"""
"""We return an error given an invalid cache_size"""
exit=1)
"""We return an error given an invalid templates_dir"""
"""We return an error given an invalid type option."""
invalid_type = "weblogic"
# ensure we work with the supported type
"""We can perform a series of HTTP requests against the BUI."""
"esc_full_fmri": esc_full_fmri}
# a series of BUI paths we should be able to access
paths = [
"/",
"/default/en/index.shtml",
"/default/en/catalog.shtml",
"/default/en/search.shtml",
"/usr/test2/en/catalog.shtml",
"/depot/default/en/search.shtml?token=pkg&action=Search"
]
try:
except HTTPError as e:
url_path, e))
raise
for p in paths:
# test that pkg.depot-config detects missing repos
# test that when we break one of the repositories we're
# serving, the remaining repositories are still accessible
# from the bui. We need to fix the repo dir before rebuilding
# the configuration, then break it once the depot has started.
# check the first request to the BUI works as expected
# and check that we get a 404 for the missing repo
try:
except HTTPError as e:
if e.code == 404:
bad_url))
# check that we can still reach other valid paths
paths = [
"/",
"/default/en/index.shtml",
"/default/en/catalog.shtml",
"/default/en/search.shtml",
]
for p in paths:
"""A depot-config can act as a repository server for pkg(1)
clients, with all functionality supported."""
# publish some sample packages to our repositories
# test that we can access the default publisher
# test that we can access specific publishers, this time from
# a different repository, served by the same depot-config.
# publish a new package, and ensure we can install it
# add a new publisher to an existing repository and ensure it
# is visible from the repository
"""A depot-config can act as a repository server for pkgrecv(1)
clients."""
# gather the FMRIs we published and the URL-quoted version
# pull down raw package contents
# Quickly sanity check the contents
# grab one of the manifests we just downloaded, and check that
# the file content is present and correct.
"""Test that only the 'pkgrepo refresh' command works with the
depot-config only when the -A flag is enabled and only on
the repository that has a writable root. Test that the index
does indeed get updated when a refresh is performed and that
new package contents are visible."""
# we have a search index on rurl
# we have no search index on nosearch_rurl
# allow index refreshes for repositories that support them
# (ie. have a writable root)
# verify that list commands work
# rebuild, remove and set commands should fail, the latter two
# with exit code 2
exit=2)
# verify that status works
# verify search works for packages in the repository
exit=1)
# Can't refresh this repo since it doesn't have a writable root
# verify that search fails for repositories that don't have
# a pre-existing search index in the repository
# publish a new package, and verify it doesn't appear in the
# search results for the repo with the writable_root
# now refresh the index
# there isn't a synchronous option to pkgrepo, so wait a bit
# then make sure we do see this new package.
# we should now get search results for that new package
# ensure that refresh --no-catalog works, but refresh --no-index
# does not.
# check that when we start the depot without -A, we cannot
# issue refresh commands.
"""Test that the correct Content-Type and Cache-control headers
are sent from the depot for the responses that we care about."""
# Create an image so we have something to search with.
# This technically isn't necessary anymore, but the test suite
# runs with some debug flags to make it (intentionally)
# difficult to mess with the root image of the test system
# (even though calling 'pkg search -s' would never actually
# modify it) Creating an image is just the easier thing to do
# here.
"pkg:/", "")
# a dictionary of paths we should be able to access, along with
# expected header (name,value) pairs for each
paths = {
[("Content-Type", "application/vnd.pkg5.info")],
[("Cache-Control", "no-cache")],
[("Cache-Control",
"must-revalidate, no-transform, max-age=31536000"),
[("Cache-Control", "no-cache"),
[("Cache-Control",
"must-revalidate, no-transform, max-age=31536000"),
("Content-Type", "application/data")]
}
"""Check that HTTP 'header' from 'url' contains an
expected value 'value'."""
try:
else:
# HTTPMessage inherits from
# email.Message in Python 3 so that it
# has a different method
if value in h:
return True
except Exception as e:
url, e))
return ret
"{0} did not contain the header {1}={2}".format(
"""Test that the fragment httpd.conf generated by pkg.depot-config
can be used in a standard Apache configuration, but that
pkg(1) admin and search operations fail."""
# We shouldn't be able to supply a writable root when running
# in fragment mode
"-P testpkg5".format(
"-P testpkg5".format(
# Start an Apache instance
# verify the instance is definitely the one using our custom
"Error getting pkg5-server-status")
# add publishers for the two repositories being served by this
# Apache instance
# install packages from the two different publishers in the
# first repository
# install a package from the second repository
# we can't perform remote search or admin operations, since
# we've no supporting mod_wsgi process.
"""Tests that exercise the pkg.depot-config CLI as well as checking the
functionality of the depot-config itself for configuring https service.
This test class will fail if not run as root, since many of the tests
use 'pkg.depot-config -a' which will attempt to chown a directory to
pkg5srv:pkg5srv.
"""
"""We return an error given an invalid option combo."""
"ido_exist_cert")
"ido_exist_key")
"tmp/ido_exist_key"])
# Test that without --https, providing certs or keys will fail.
"providing cert or key should fail but succeeded "
"instead.")
"providing cert or key should fail but succeeded "
"instead.")
"providing cert or key should fail but succeeded "
"instead.")
# Checking that HTTPS is not supported in fragment mode.
"providing cert or key should fail but succeeded "
"instead.")
"""We return errors if the option in a combo is not specified
at the same time."""
"ido_exist_cert")
"ido_exist_key")
"tmp/ido_exist_key"])
"""We return an error given an invalid cer_key_dir."""
"--cert-key-dir {0}".format(
"""We return an error given an non-exist cert or key."""
"idonot_exist_cert")
"idonot_exist_key")
"ido_exist_cert")
"ido_exist_key")
"tmp/ido_exist_key"])
# Test checking user provided server cert works.
# Test checking user provided server key works.
# Test checking user provided cert chain file works.
"--cert {0} --key {1} --cert-chain {2}".format(
# Test checking user provided CA cert file works.
"--ca-cert {0} --ca-key {1} --cert-key-dir {2}".format(
# Test checking user provided CA key file works.
"--ca-cert {0} --ca-key {1} --cert-key-dir {2}".format(
"some_fake_file")
# Test with invalid fmri.
"--https --cert-key-dir {0} --smf-fmri {1}".format(
"setting should fail but succeeded instead.")
# Test with wrong fmri.
wrong_fmri = "pkg/server:default"
"--https --cert-key-dir {0} --smf-fmri {1}".format(
"setting should fail but succeeded instead.")
"""Test that https functionality works as expected."""
"cert_key")
"--https -T {6} -h localhost --cert-key-dir {7}".format(
# Start an Apache instance
# add publishers for the two repositories being served by this
# Apache instance.
# install packages from the two different publishers in the
# first repository
# install a package from the second repository
# we can't perform remote search or admin operations, since
# we've no supporting mod_wsgi process.
"""Test that https functionality with cert chain works as
expected."""
"cert_key_dir")
"ta_cert.pem")
"ca_ta_cert.pem")
"--https -T {6} -h localhost --cert {7} --key {8} "
"--cert-chain {9}".format(
# Start an Apache instance
# add publishers for the two repositories being served by this
# Apache instance.
# install packages from the two different publishers in the
# first repository
# install a package from the second repository
"""Test that pkg.depot-config functionality with provided
ca certificate and key works as expected."""
"cert_key_dir")
"ta_cert.pem")
"--https -T {6} -h localhost --ca-cert {7} --ca-key {8} "
"--cert-key-dir {9}".format(
# Start an Apache instance
# add publishers for the two repositories being served by this
# Apache instance.
# install packages from the two different publishers in the
# first repository
# install a package from the second repository
if __name__ == "__main__":