Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Puppet (apply) provisioning plugin #629

Merged
merged 29 commits into from
Feb 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
030aedd
crude design attempt for a puppet-apply provisioning plugin
igalic Feb 3, 2019
e15d43e
remove iocage (c) from copy/pasted code
igalic Feb 3, 2019
b979db8
add puppet to available provisioning modules
gronke Feb 3, 2019
4cb9e05
break cli example in puppet provisioner in multiple lines
gronke Feb 3, 2019
c5063d6
pkgs is a property and needs to be accessed by .
igalic Feb 3, 2019
312ed37
be consistent with naming: use pluginDefinition as variable name
igalic Feb 4, 2019
0ea62f4
add local & remote property to our plugin definition
igalic Feb 4, 2019
c6a45c5
puppet: use persistent dataset
igalic Feb 4, 2019
3e925a3
remove unused copy/pasted function
igalic Feb 4, 2019
8fa883d
only clone the repo if it doesnt already exist
igalic Feb 4, 2019
ca19958
only mount plugin dataset as rw when it needs to be rw
igalic Feb 4, 2019
5a266d1
write postinstall (provisioning) script
igalic Feb 4, 2019
35359c7
fix flake8 warnings
igalic Feb 4, 2019
e19087f
fix scope and name in puppet provisioning
gronke Feb 5, 2019
f48a1b5
puppet provisioning uses urllib.parse
gronke Feb 5, 2019
87e3a43
rename url to source and allow it to be AbsolutePath
igalic Feb 6, 2019
010047c
add --debug to puppet, libioc will filter it out anyway
igalic Feb 6, 2019
12f538a
correct puppet provisioner url to source property
gronke Feb 6, 2019
0b22678
use interpolation for used variables
gronke Feb 6, 2019
8c946e5
raise correct ValueError instead of TypeError in Types.AbsolutePath a…
gronke Feb 7, 2019
c6ec4e9
move path validation methods from config to Resource
gronke Feb 7, 2019
b98a7d9
ToDo: remove unused jailed argument
gronke Feb 7, 2019
c671d88
docstring on JailGenerator._ensure_script_dir
gronke Feb 7, 2019
c14904f
refactor Provisioning
Feb 7, 2019
5adbb3b
set /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/roo…
Feb 7, 2019
d56ca12
fix typo in variable name in Fstab.insert
Feb 7, 2019
4d5ae50
puppet: fix for remote sources
igalic Feb 7, 2019
ad97934
Better documentation! for provisioning.method=puppet
igalic Feb 7, 2019
a0f8d2a
fix flake8 complaints
igalic Feb 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions libioc/Config/Jail/File/Fstab.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,7 @@ def __hash__(self) -> int:
return hash(None)


class Fstab(
libioc.Config.Jail.File.ResourceConfig,
collections.MutableSequence
):
class Fstab(collections.MutableSequence):
"""
Fstab configuration file wrapper.

Expand Down Expand Up @@ -203,10 +200,7 @@ def path(self) -> str:
path = self.file
else:
path = f"{self.jail.dataset.mountpoint}/{self.file}"
self._require_path_relative_to_resource(
filepath=path,
resource=self.jail
)
self.jail._require_relative_path(path)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a method so important for security could be made public…


return path

Expand Down Expand Up @@ -400,7 +394,16 @@ def add_line(

Use save() to write changes to the fstab file.
"""
if self.__contains__(line):
if type(line) == FstabLine:
if self.jail._is_path_relative(line["destination"]) is False:
line = FstabLine(line) # clone to prevent mutation
line["destination"] = libioc.Types.AbsolutePath("/".join([
self.jail.root_path,
line["destination"].lstrip("/")
]))

line_already_exists = self.__contains__(line)
if line_already_exists:
destination = line["destination"]
if replace is True:
self.logger.verbose(
Expand All @@ -425,11 +428,13 @@ def add_line(

if type(line) == FstabLine:
# destination is always relative to the jail resource
if line["destination"].startswith(self.jail.root_path) is False:
line["destination"] = libioc.Types.AbsolutePath("/".join([
if self.jail._is_path_relative(line["destination"]) is False:
_destination = libioc.Types.AbsolutePath("/".join([
self.jail.root_path,
line["destination"].strip("/")
]))
self.jail._require_relative_path(_destination)
line["destination"] = _destination

libioc.helpers.require_no_symlink(str(line["destination"]))

Expand All @@ -442,12 +447,17 @@ def add_line(
os.makedirs(line["destination"], 0o700)

if (auto_mount_jail and self.jail.running) is True:
destination = line["destination"]
self.jail._require_relative_path(destination)
self.logger.verbose(
f"auto-mount {destination}"
)
mount_command = [
"/sbin/mount",
"-o", line["options"],
"-t", line["type"],
line["source"],
line["destination"]
destination
]
libioc.helpers.exec(mount_command, logger=self.logger)
_source = line["source"]
Expand Down Expand Up @@ -632,7 +642,7 @@ def insert(
# find FstabAutoPlaceholderLine instead
line = list(filter(
lambda x: isinstance(x, FstabAutoPlaceholderLine),
self._line
self._lines
))[0]
real_index = self._lines.index(line)
else:
Expand Down
37 changes: 2 additions & 35 deletions libioc/Config/Jail/File/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,6 @@
import libioc.helpers_object
import libioc.LaunchableResource


class ResourceConfig:
"""Shared abstract code between various config files in a resource."""
igalic marked this conversation as resolved.
Show resolved Hide resolved

def _require_path_relative_to_resource(
self,
filepath: str,
resource: 'libioc.LaunchableResource.LaunchableResource'
) -> None:

if self._is_path_relative_to_resource(filepath, resource) is False:
raise libioc.errors.SecurityViolationConfigJailEscape(
file=filepath
)

def _is_path_relative_to_resource(
self,
filepath: str,
resource: 'libioc.LaunchableResource.LaunchableResource'
) -> bool:

real_resource_path = self._resolve_path(resource.dataset.mountpoint)
real_file_path = self._resolve_path(filepath)

return real_file_path.startswith(real_resource_path)

def _resolve_path(self, filepath: str) -> str:
return os.path.realpath(os.path.abspath(filepath))


class ConfigFile(dict):
"""Abstraction of UCL file based config files in Resources."""

Expand Down Expand Up @@ -221,7 +191,7 @@ def __getitem__(
return None


class ResourceConfigFile(ConfigFile, ResourceConfig):
class ResourceConfigFile(ConfigFile):
"""Abstraction of UCL file based config files in Resources."""

def __init__(
Expand All @@ -238,8 +208,5 @@ def __init__(
def path(self) -> str:
"""Absolute path to the file."""
path = f"{self.resource.root_dataset.mountpoint}/{self.file}"
self._require_path_relative_to_resource(
filepath=path,
resource=self.resource
)
self.resource._require_relative_path(path)
return os.path.abspath(path)
2 changes: 1 addition & 1 deletion libioc/Config/Type/JSON.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ class DatasetConfigJSON(
libioc.Config.Dataset.DatasetConfig,
ConfigJSON
):
"""ResourceConfig in JSON format."""
"""ConfigFile in JSON format."""

pass
2 changes: 1 addition & 1 deletion libioc/Config/Type/UCL.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ class DatasetConfigUCL(
libioc.Config.Dataset.DatasetConfig,
ConfigUCL
):
"""ResourceConfig in UCL format."""
"""ConfigFile in UCL format."""

pass
11 changes: 10 additions & 1 deletion libioc/Jail.py
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ def _wrap_hook_script_command(
self,
commands: typing.Optional[typing.Union[str, typing.List[str]]],
ignore_errors: bool=True,
jailed: bool=False,
jailed: bool=False, # ToDo: remove unused argument
write_env: bool=True
) -> typing.List[str]:

Expand Down Expand Up @@ -862,6 +862,7 @@ def _run_hook(self, hook_name: str) -> typing.Optional[
raise NotImplementedError("_run_hook only supports start/stop")

def _ensure_script_dir(self) -> None:
"""Ensure that the launch scripts dir exists."""
realpath = os.path.realpath(self.launch_script_dir)
if realpath.startswith(self.dataset.mountpoint) is False:
raise libioc.errors.SecurityViolationConfigJailEscape(
Expand Down Expand Up @@ -2174,6 +2175,14 @@ def env(self) -> typing.Dict[str, str]:

jail_env["IOC_JAIL_PATH"] = self.root_dataset.mountpoint
jail_env["IOC_JID"] = str(self.jid)
jail_env["PATH"] = ":".join((
"/sbin",
"/bin",
"/usr/sbin",
"/usr/bin",
"/usr/local/sbin",
"/usr/local/bin",
))
igalic marked this conversation as resolved.
Show resolved Hide resolved

return jail_env

Expand Down
89 changes: 85 additions & 4 deletions libioc/Provisioning/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,90 @@
# POSSIBILITY OF SUCH DAMAGE.
"""iocage provisioning prototype."""
igalic marked this conversation as resolved.
Show resolved Hide resolved
import typing
import urllib.parse

import libioc.errors
import libioc.Types
import libioc.helpers
import libioc.Provisioning.ix
import libioc.Provisioning.puppet
gronke marked this conversation as resolved.
Show resolved Hide resolved

_SourceType = typing.Union[
urllib.parse.ParseResult,
libioc.Types.AbsolutePath,
]
_SourceInputType = typing.Union[_SourceType, str]

class Source(str):

_value: _SourceType

def __init__(
self,
value: _SourceInputType
) -> None:
self.value = value

@property
def value(self) -> _SourceType:
return self._value

@value.setter
def value(self, value: _SourceInputType) -> None:

if isinstance(value, libioc.Types.AbsolutePath) is True:
self._value = typing.Cast(libioc.Types.AbsolutePath, value)
return
elif isinstance(value, urllib.parse.ParseResult) is True:
url = typing.Cast(urllib.parse.ParseResult, value)
self.__require_valid_url(url)
self._value = _value
return
elif isinstance(value, str) is False:
raise TypeError(
f"Input must be URL, AbsolutePath or str, but was {type(value)}"
)

try:
self._value = libioc.Types.AbsolutePath(value)
return
except ValueError as e:
pass

try:
url = urllib.parse.urlparse(value)
self.__require_valid_url(url)
self._value = url
return
except ValueError:
pass

raise ValueError("Provisioning Source must be AbsolutePath or URL")

@property
def local(self) -> bool:
"""Return True when the source is local."""
return (isinstance(self.value, libioc.Types.AbsolutePath) is True)

@property
def remote(self) -> bool:
"""Return True when the source is a remote URL."""
return (self.local is False)

def __require_valid_url(self, url: urllib.parse.ParseResult) -> None:
if url.scheme not in ("https", "http", "ssh", "git"):
raise ValueError(f"Invalid Source Scheme: {url.scheme}")

def __str__(self) -> str:
"""Return the Provisioning Source as string."""
value = self.value
if isinstance(value, urllib.parse.ParseResult) is True:
return value.geturl()
else:
return str(value)

def __repr__(self) -> str:
return f"<Source '{self.__str__()}'>"


class Prototype:
Expand All @@ -46,14 +126,14 @@ def method(self) -> str:
self.__METHOD

@property
def source(self) -> typing.Optional[str]:
def source(self) -> typing.Optional[Source]:
config_value = self.jail.config["provisioning.source"]
return None if (config_value is None) else str(config_value)
return None if (config_value is None) else Source(config_value)

@property
def rev(self) -> typing.Optional[str]:
config_value = self.jail.config["provisioning.rev"]
return None if (config_value is None) else str(config_value)
return None if (config_value is None) else str(Source(config_value))

def check_requirements(self) -> None:
"""Check requirements before executing the provisioner."""
Expand Down Expand Up @@ -84,7 +164,8 @@ def __available_provisioning_modules(
self
) -> typing.Dict[str, Prototype]:
return dict(
ix=libioc.Provisioning.ix
ix=libioc.Provisioning.ix,
puppet=libioc.Provisioning.puppet
igalic marked this conversation as resolved.
Show resolved Hide resolved
)

@property
Expand Down
Loading