Repository: cekit/cekit

Issue:
Disabling content sets using YAML null values is not possible
**Describe the solution you'd like**
The yaml's remove character is not accepted by CEKit thus not possible to remove a property from the image.yaml using overrides file.

Example: given the following image.yaml file: 

```yaml
schema_version: 1

name: "image-name"
version: "1.1"
from: "ubi8"
labels:
  - name: "com.redhat.component"
    value: "image"
packages:
  content_sets_file: content_sets.yml
  install:
    - java-1.8.0-openjdk-headless
```

And supposing we want the remove the content_sets_file property using an overrides file:

```yaml
schema_version: 1

name: "rhpam-7/rhpam7-dev-apb"
from: "ansibleplaybookbundle/apb-base:v3.11"

packages:
  content_sets_file: ~
```

It will fail with the following message:

```
TypeError: join() argument must be str or bytes, not 'NoneType'
```

using `null` produces the same result.


Discussion:

Patch:
diff --git a/cekit/builder.py b/cekit/builder.py
index 7b2b163..c03bf46 100644
--- a/cekit/builder.py
+++ b/cekit/builder.py
@@ -29,10 +29,15 @@ class Command(object):
     def prepare(self):
         pass
 
+    def before_run(self):
+        pass
+
     def run(self):
         raise CekitError(
             "Command.run() method is not implemented for '{}' command and '{}' type. Please report it!".format(self._command, self._type))
 
+    def after_run(self):
+        pass
 
 class Builder(Command):
     """
@@ -57,8 +62,16 @@ class Builder(Command):
             LOGGER.info("The --dry-run parameter was specified, build will not be executed")
             return
 
+        self.before_run()
+
         self.run()
 
+        self.after_run()
+
+    def before_run(self):
+        LOGGER.debug("Checking CEKit build dependencies...")
+        self.dependency_handler.handle(self)
+
     def prepare(self):
         if self.build_engine == 'docker' or self.build_engine == 'buildah' or self.build_engine == "podman":
             from cekit.generator.docker import DockerGenerator as generator_impl
@@ -87,6 +100,3 @@ class Builder(Command):
 
         self.generator.init()
         self.generator.generate(self.build_engine)
-
-        LOGGER.debug("Checking CEKit build dependencies...")
-        self.dependency_handler.handle(self)
diff --git a/cekit/builders/docker_builder.py b/cekit/builders/docker_builder.py
index db3b59a..5aaea09 100644
--- a/cekit/builders/docker_builder.py
+++ b/cekit/builders/docker_builder.py
@@ -4,8 +4,6 @@ import re
 import sys
 import traceback
 
-import yaml
-
 from cekit.builder import Builder
 from cekit.errors import CekitError
 
@@ -20,7 +18,8 @@ except ImportError:
     pass
 
 try:
-    # Docker Python library, the old one
+    # Docker Python library, the new one
+    import docker
     from docker.api.client import APIClient as APIClientClass
 except ImportError:
     pass
@@ -34,7 +33,8 @@ except ImportError:
     pass
 
 try:
-    # Docker Python library, the new one
+    # Docker Python library, the old one
+    import docker  # pylint: disable=ungrouped-imports
     from docker.client import Client as APIClientClass  # pylint: disable=ungrouped-imports
 except ImportError:
     pass
@@ -48,19 +48,6 @@ class DockerBuilder(Builder):
     def __init__(self, common_params, params):
         super(DockerBuilder, self).__init__('docker', common_params, params)
 
-        # Default Docker daemon connection timeout 10 minutes
-        # It needs to be high enough to allow Docker daemon to export the
-        # image for squashing.
-        try:
-            self.timeout = int(os.getenv('DOCKER_TIMEOUT', '600'))
-        except ValueError:
-            raise CekitError("Provided timeout value: %s cannot be parsed as integer, exiting." %
-                             os.getenv('DOCKER_TIMEOUT'))
-
-        if self.timeout <= 0:
-            raise CekitError(
-                "Provided timeout value needs to be greater than zero, currently: %s, exiting." % self.timeout)
-
     @staticmethod
     def dependencies():
         deps = {}
@@ -157,7 +144,7 @@ class DockerBuilder(Builder):
                 msg = "Image build failed with a yum error and you don't " \
                     "have any yum repository configured, please check " \
                     "your image/module descriptor for proper repository " \
-                    " definitions."
+                    "definitions."
 
             raise CekitError(msg, ex)
 
@@ -181,6 +168,64 @@ class DockerBuilder(Builder):
             else:
                 docker_client.tag(image_id, tag)
 
+    def _docker_client(self):
+        LOGGER.debug("Preparing Docker client...")
+
+        # Default Docker daemon connection timeout 10 minutes
+        # It needs to be high enough to allow Docker daemon to export the
+        # image for squashing.
+        try:
+            timeout = int(os.getenv('DOCKER_TIMEOUT', '600'))
+        except ValueError:
+            raise CekitError("Provided timeout value: '{}' cannot be parsed as integer, exiting.".format(
+                os.getenv('DOCKER_TIMEOUT')))
+
+        if timeout <= 0:
+            raise CekitError(
+                "Provided timeout value needs to be greater than zero, currently: '{}', exiting.".format(timeout))
+
+        params = {"version": "1.22"}
+        params.update(docker.utils.kwargs_from_env())
+        params["timeout"] = timeout
+
+        try:
+            client = APIClientClass(**params)
+        except docker.errors.DockerException as e:
+            LOGGER.error("Could not create Docker client, please make sure that you "
+                         "specified valid parameters in the 'DOCKER_HOST' environment variable, "
+                         "examples: 'unix:///var/run/docker.sock', 'tcp://192.168.22.33:1234'")
+            raise CekitError("Error while creating the Docker client", e)
+
+        if client and self._valid_docker_connection(client):
+            LOGGER.debug("Docker client ready and working")
+            LOGGER.debug(client.version())
+            return client
+
+        LOGGER.error(
+            "Could not connect to the Docker daemon at '{}', please make sure the Docker "
+            "daemon is running.".format(client.base_url))
+
+        if client.base_url.startswith('unix'):
+            LOGGER.error(
+                "Please make sure the Docker socket has correct permissions.")
+
+        if os.environ.get('DOCKER_HOST'):
+            LOGGER.error("If Docker daemon is running, please make sure that you specified valid "
+                         "parameters in the 'DOCKER_HOST' environment variable, examples: "
+                         "'unix:///var/run/docker.sock', 'tcp://192.168.22.33:1234'. You may "
+                         "also need to specify 'DOCKER_TLS_VERIFY', and 'DOCKER_CERT_PATH' "
+                         "environment variables.")
+
+        raise CekitError("Cannot connect to Docker daemon")
+
+    def _valid_docker_connection(self, client):
+        try:
+            return client.ping()
+        except requests.exceptions.ConnectionError:
+            pass
+
+        return False
+
     def run(self):
         tags = self.params.tags
 
@@ -190,7 +235,7 @@ class DockerBuilder(Builder):
         LOGGER.info("Building container image using Docker...")
         LOGGER.debug("Building image with tags: '%s'" % "', '".join(tags))
 
-        docker_client = APIClientClass(version="1.22", timeout=self.timeout)
+        docker_client = self._docker_client()
 
         # Build image
         image_id = self._build_with_docker(docker_client)
diff --git a/cekit/builders/osbs.py b/cekit/builders/osbs.py
index 8d01362..bd70bd9 100644
--- a/cekit/builders/osbs.py
+++ b/cekit/builders/osbs.py
@@ -80,10 +80,10 @@ class OSBSBuilder(Builder):
 
         return deps
 
-    def prepare(self):
+    def before_run(self):
         """Prepares dist-git repository for OSBS build."""
 
-        super(OSBSBuilder, self).prepare()
+        super(OSBSBuilder, self).before_run()
 
         self.prepare_dist_git()
         self.copy_to_dist_git()
diff --git a/cekit/descriptor/image.py b/cekit/descriptor/image.py
index 0264122..873dde9 100644
--- a/cekit/descriptor/image.py
+++ b/cekit/descriptor/image.py
@@ -241,11 +241,26 @@ class Image(Descriptor):
             if override.packages.manager:
                 self.packages._descriptor['manager'] = override.packages.manager
 
-            if override.packages.content_sets:
-                self.packages.content_sets = _merge_descriptors(
-                    override.packages.content_sets, self.packages.content_sets)
-            elif override.packages.content_sets_file:
-                self.packages.content_sets_file = override.packages.content_sets_file
+            # If the key is set (value could be None!)
+            if 'content_sets' in override.packages:
+                # If value is different than None, merge it
+                if override.packages.content_sets:
+                    self.packages.content_sets = _merge_descriptors(
+                        override.packages.content_sets, self.packages.content_sets)
+                else:
+                    # If key exists and value is None - remove it from the main packages section
+                    self.packages._descriptor.pop('content_sets', None)
+
+            # If the key is set (value could be None!)
+            if 'content_sets_file' in override.packages:
+                # If value is different than None, set it
+                if override.packages.content_sets_file:
+                    self.packages.content_sets_file = override.packages.content_sets_file
+                else:
+                    # If key exists and value is None - remove it from the main packages section
+                    # Remove 'content_sets' too, because this is where it should already be translated into
+                    self.packages._descriptor.pop('content_sets_file', None)
+                    self.packages._descriptor.pop('content_sets', None)
 
             if override.osbs != None:
                 self.osbs = override.osbs.merge(self.osbs)
diff --git a/cekit/descriptor/packages.py b/cekit/descriptor/packages.py
index d0dc740..ecbd7b6 100644
--- a/cekit/descriptor/packages.py
+++ b/cekit/descriptor/packages.py
@@ -42,7 +42,8 @@ map:
 
 
 class Packages(Descriptor):
-    """Object representing Pakcages
+    """
+    Object representing packages
 
     Args:
       descriptor - yaml containing Packages section
@@ -52,10 +53,16 @@ class Packages(Descriptor):
         self.schemas = packages_schema
         self.descriptor_path = descriptor_path
         super(Packages, self).__init__(descriptor)
-        if ('content_sets_file' in descriptor and 'content_sets' in descriptor):
-            raise CekitError("You cannot specify content_sets and content_sets_file together!")
 
-        if 'content_sets_file' in descriptor:
+        # If 'content_sets' and 'content_sets_file' are defined at the same time
+        if set(['content_sets', 'content_sets_file']).issubset(set(descriptor.keys())):
+            raise CekitError(
+                "You cannot specify 'content_sets' and 'content_sets_file' together in the packages section!")
+
+        # If the 'content_sets_file' key is set and is not None we need to read the specified
+        # file and make it available in the 'content_sets' key. The 'content_sets_file' key is removed
+        # afterwards.
+        if descriptor.get('content_sets_file', None):
             content_sets_file = os.path.join(self.descriptor_path, descriptor['content_sets_file'])
 
             if not os.path.exists(content_sets_file):
diff --git a/cekit/version.py b/cekit/version.py
index 35b5f62..69d1a00 100644
--- a/cekit/version.py
+++ b/cekit/version.py
@@ -1,2 +1,2 @@
-version = "3.1.dev0"
+version = "3.2.dev0"
 schema_version = 2
diff --git a/docs/handbook/building/builder-engines.rst b/docs/handbook/building/builder-engines.rst
index ccd7a71..668c0c6 100644
--- a/docs/handbook/building/builder-engines.rst
+++ b/docs/handbook/building/builder-engines.rst
@@ -30,6 +30,40 @@ Example
 
         $ cekit build docker
 
+Docker environment variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It is possible to use environment variables to let CEKit know where is the Docker daemon
+located it should connect to.
+
+.. note::
+    Read more about `Docker daemon settings related to exposing it to clients <https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option>`__.
+
+By default, if you do not specify anything, **CEKit will try to use a locally running Docker daemon**.
+
+If you need to customize this behavior (for example when you want to use Docker daemon
+running in a VM) you can set following environment variables:
+
+``DOCKER_HOST``
+    The ``DOCKER_HOST`` environment variable is where you specify where the Daemon is running. It supports
+    multiple protocols, but the most widely used ones are: ``unix://`` (where you specify path to a local
+    socket) and ``tcp://`` (where you can define host location and port).
+
+    Examples of ``DOCKER_HOST``: ``unix:///var/run/docker.sock``, ``tcp://192.168.22.33:1234``.
+
+    Depending how your daemon is configured you may need to configure settings related to encryption.
+
+    .. code-block:: bash
+
+        # Connect to a remote Docker daemon
+        $ DOCKER_HOST="tcp://192.168.22.33:1234" cekit build docker
+``DOCKER_TLS_VERIFY``
+    You can set ``DOCKER_TLS_VERIFY`` to a non-empty value to indicate that the TLS verification should
+    take place. By default certificate verification is **disabled**.
+``DOCKER_CERT_PATH``
+    You can point ``DOCKER_CERT_PATH`` environment variable to a directory containing certificates to use when
+    connecting to the Docker daemon.
+
 
 OSBS builder
 ---------------------------


Test patch:
diff --git a/tests/images/image-gh-533-disable-content-sets-file.yaml b/tests/images/image-gh-533-disable-content-sets-file.yaml
new file mode 100644
index 0000000..99b83ad
--- /dev/null
+++ b/tests/images/image-gh-533-disable-content-sets-file.yaml
@@ -0,0 +1,10 @@
+schema_version: 1
+
+name: "test/content-sets-disable"
+version: "dev"
+from: "centos:7"
+
+packages:
+  content_sets_file: content_sets.yml
+  install:
+    - openssl
\ No newline at end of file
diff --git a/tests/images/gh-538-encoding-mac/image.yaml b/tests/images/image-gh-538-py27-encoding.yaml
similarity index 100%
rename from tests/images/gh-538-encoding-mac/image.yaml
rename to tests/images/image-gh-538-py27-encoding.yaml
diff --git a/tests/test_builder.py b/tests/test_builder.py
index 74334f5..20707e3 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -444,6 +444,7 @@ def test_osbs_copy_artifacts_to_dist_git(mocker, tmpdir, artifact, src, target):
 
     with mocker.patch('cekit.tools.get_brew_url', side_effect=subprocess.CalledProcessError(1, 'command')):
         builder.prepare()
+        builder.before_run()
 
     dist_git_class.assert_called_once_with(os.path.join(
         str(tmpdir), 'osbs', 'repo'), str(tmpdir), 'repo', 'branch')
@@ -460,6 +461,68 @@ def test_docker_builder_defaults():
     assert builder.params.tags == ['foo', 'bar']
 
 
+def test_osbs_dist_git_sync_called(mocker, tmpdir):
+    mocker.patch('cekit.tools.DependencyHandler.handle')
+
+    image_descriptor = {
+        'schema_version': 1,
+        'from': 'centos:latest',
+        'name': 'test/image',
+        'version': '1.0',
+        'labels': [{'name': 'foo', 'value': 'bar'}, {'name': 'labela', 'value': 'a'}],
+        'osbs': {
+            'repository': {
+                'name': 'repo',
+                'branch': 'branch'
+            }
+        }
+    }
+
+    builder = create_builder_object(
+        mocker, 'osbs', {}, {'descriptor': yaml.dump(image_descriptor), 'target': str(tmpdir)})
+
+    prepare_dist_git = mocker.patch.object(builder, 'prepare_dist_git')
+    copy_to_dist_git = mocker.patch.object(builder, 'copy_to_dist_git')
+    run = mocker.patch.object(builder, 'run')
+
+    builder.execute()
+
+    prepare_dist_git.assert_called_once_with()
+    copy_to_dist_git.assert_called_once_with()
+    run.assert_called_once_with()
+
+
+def test_osbs_dist_git_sync_NOT_called_when_dry_run_set(mocker, tmpdir):
+    mocker.patch('cekit.tools.DependencyHandler.handle')
+
+    image_descriptor = {
+        'schema_version': 1,
+        'from': 'centos:latest',
+        'name': 'test/image',
+        'version': '1.0',
+        'labels': [{'name': 'foo', 'value': 'bar'}, {'name': 'labela', 'value': 'a'}],
+        'osbs': {
+            'repository': {
+                'name': 'repo',
+                'branch': 'branch'
+            }
+        }
+    }
+
+    builder = create_builder_object(
+        mocker, 'osbs', {'dry_run': True}, {'descriptor': yaml.dump(image_descriptor), 'target': str(tmpdir)})
+
+    prepare_dist_git = mocker.patch.object(builder, 'prepare_dist_git')
+    copy_to_dist_git = mocker.patch.object(builder, 'copy_to_dist_git')
+    run = mocker.patch.object(builder, 'run')
+
+    builder.execute()
+
+    prepare_dist_git.assert_not_called()
+    copy_to_dist_git.assert_not_called()
+    run.assert_not_called()
+
+
 def test_docker_build_default_tags(mocker):
     builder = DockerBuilder(Map({'target': 'something'}), Map())
 
diff --git a/tests/test_unit_descriptor.py b/tests/test_unit_descriptor.py
index 0aa50fb..6326e36 100644
--- a/tests/test_unit_descriptor.py
+++ b/tests/test_unit_descriptor.py
@@ -85,6 +85,51 @@ def test_packages_invalid_old_repository_definition():
             - pkg-foo"""), "a/path/image.yaml")
 
 
+def test_packages_content_sets_and_content_sets_file():
+    with pytest.raises(CekitError, match=r"You cannot specify 'content_sets' and 'content_sets_file' together in the packages section!"):
+        Packages(
+            {
+                'content_sets': {
+                    'x86_64': ['rhel-server-rhscl-7-rpms', 'rhel-7-server-rpms']
+                },
+                'content_sets_file': "a_path.yaml"
+            },
+            "a/path"
+        )
+
+
+def test_packages_content_sets():
+    pkg = Packages(
+        {
+            'content_sets': {
+                'x86_64': ['rhel-server-rhscl-7-rpms', 'rhel-7-server-rpms']
+            },
+            'install': ['package_a', 'package_b']
+        },
+        "a/path"
+    )
+
+    assert 'package_a' in pkg['install']
+    assert 'content_sets_file' not in pkg
+
+
+def test_packages_content_sets_file(mocker):
+    with mocker.mock_module.patch('cekit.descriptor.packages.os.path.exists') as exists_mock:
+        exists_mock.return_value = True
+        with mocker.mock_module.patch('cekit.descriptor.packages.open', mocker.mock_open(read_data='{"a": 12}')):
+            pkg = Packages(
+                {
+                    'content_sets_file': "a_path.yaml",
+                    'install': ['package_a', 'package_b']
+                },
+                "a/path"
+            )
+
+    assert 'package_a' in pkg['install']
+    assert 'content_sets_file' not in pkg
+    assert pkg['content_sets'] == {'a': 12}
+
+
 def test_image():
     image = Image(yaml.safe_load("""
     from: foo
diff --git a/tests/test_unit_image.py b/tests/test_unit_image.py
new file mode 100644
index 0000000..d046ce4
--- /dev/null
+++ b/tests/test_unit_image.py
@@ -0,0 +1,52 @@
+import pytest
+import yaml
+
+from cekit.descriptor import Image, Packages, Overrides
+
+
+def test_image_overrides_with_content_sets_none():
+    image = Image(yaml.safe_load("""
+    from: foo
+    name: test/foo
+    version: 1.9
+    packages:
+      install:
+        - abc
+        - def
+      content_sets:
+        arch:
+          - namea
+          - nameb
+    """), 'foo')
+
+    assert image.packages.content_sets == {'arch': ['namea', 'nameb']}
+    assert 'content_sets_file' not in image.packages
+
+    image.apply_image_overrides([Overrides({'packages': {'content_sets': None}}, "a/path")])
+
+    assert 'content_sets' not in image.packages
+    assert 'content_sets_file' not in image.packages
+
+
+def test_image_overrides_with_content_sets_file_none(mocker):
+    with mocker.mock_module.patch('cekit.descriptor.packages.os.path.exists') as exists_mock:
+        exists_mock.return_value = True
+        with mocker.mock_module.patch('cekit.descriptor.packages.open', mocker.mock_open(read_data='{"arch": ["a", "b"]}')):
+            image = Image(yaml.safe_load("""
+                from: foo
+                name: test/foo
+                version: 1.9
+                packages:
+                    install:
+                        - abc
+                         def
+                    content_sets_file: cs.yaml
+                """), 'foo')
+
+    assert image.packages.content_sets == {'arch': ['a', 'b']}
+    assert 'content_sets_file' not in image.packages
+
+    image.apply_image_overrides([Overrides({'packages': {'content_sets_file': None}}, "a/path")])
+
+    assert 'content_sets' not in image.packages
+    assert 'content_sets_file' not in image.packages
diff --git a/tests/test_validate.py b/tests/test_validate.py
index 7594b28..4d6a014 100644
--- a/tests/test_validate.py
+++ b/tests/test_validate.py
@@ -918,8 +918,9 @@ def test_incorrect_override_file(mocker, tmpdir, caplog):
     assert "Key 'wrong!' was not defined" in caplog.text
 
 
-def test_simple_image_build_no_docker_perm(tmpdir, mocker, caplog):
-    mocker.patch('urllib3.connectionpool.HTTPConnectionPool.urlopen', side_effect=PermissionError())
+def test_simple_image_build_error_local_docker_socket_permission_denied(tmpdir, mocker, caplog):
+    mocker.patch('urllib3.connectionpool.HTTPConnectionPool.urlopen',
+                 side_effect=PermissionError())
 
     image_dir = str(tmpdir.mkdir('source'))
     copy_repos(image_dir)
@@ -931,15 +932,10 @@ def test_simple_image_build_no_docker_perm(tmpdir, mocker, caplog):
                                     'build',
                                     'docker'])
 
-    if sys.version_info.major == 2:
-        message = "Unknown ConnectionError from docker ; is the daemon started and correctly setup"
-    else:
-        message = "Unable to contact docker daemon. Is it correctly setup"
-
-    assert message in caplog.text
+    assert "Could not connect to the Docker daemon at 'http+docker://localhost', please make sure the Docker daemon is running" in caplog.text
 
 
-def test_simple_image_build_no_docker_start(tmpdir, mocker, caplog):
+def test_simple_image_build_error_local_docker_stopped(tmpdir, mocker, caplog):
     mocker.patch('urllib3.connectionpool.HTTPConnectionPool.urlopen',
                  side_effect=FileNotFoundError())
 
@@ -949,33 +945,79 @@ def test_simple_image_build_no_docker_start(tmpdir, mocker, caplog):
     with open(os.path.join(image_dir, 'image.yaml'), 'w') as fd:
         yaml.dump(image_descriptor, fd, default_flow_style=False)
 
-    if sys.version_info.major == 2:
-        message = "Unknown ConnectionError from docker ; is the daemon started and correctly setup"
-    else:
-        message = "Unable to contact docker daemon. Is it started"
-
     run_cekit_exception(image_dir,
                         ['-v',
                          'build',
                          'docker'])
 
-    assert message in caplog.text
+    assert "Could not connect to the Docker daemon at 'http+docker://localhost', please make sure the Docker daemon is running" in caplog.text
+
+
+def test_simple_image_build_error_connection_error_remote_docker_with_custom_docker_host(tmpdir, mocker, monkeypatch, caplog):
+    mocker.patch('urllib3.connectionpool.HTTPConnectionPool.urlopen',
+                 side_effect=PermissionError())
 
+    monkeypatch.setenv("DOCKER_HOST", "tcp://127.0.0.1:1234")
 
+    image_dir = str(tmpdir.mkdir('source'))
+    copy_repos(image_dir)
+
+    with open(os.path.join(image_dir, 'image.yaml'), 'w') as fd:
+        yaml.dump(image_descriptor, fd, default_flow_style=False)
+
+    run_cekit_exception(image_dir, ['-v',
+                                    'build',
+                                    'docker'])
+
+    assert "Could not connect to the Docker daemon at 'http://127.0.0.1:1234', please make sure the Docker daemon is running" in caplog.text
+    assert "If Docker daemon is running, please make sure that you specified valid parameters in the 'DOCKER_HOST' environment variable, examples: 'unix:///var/run/docker.sock', 'tcp://192.168.22.33:1234'. You may also need to specify 'DOCKER_TLS_VERIFY', and 'DOCKER_CERT_PATH' environment variables" in caplog.text
+
+
+# https://github.com/cekit/cekit/issues/538
 @pytest.mark.skipif(platform.system() == 'Darwin', reason="Disabled on macOS, cannot run Docker")
 def test_proper_decoding(tmpdir, caplog):
     image_dir = str(tmpdir.mkdir('source'))
 
     shutil.copy2(
-        os.path.join(os.path.dirname(__file__), 'images', 'gh-538-encoding-mac', 'image.yaml'),
+        os.path.join(os.path.dirname(__file__), 'images', 'image-gh-538-py27-encoding.yaml'),
+        os.path.join(image_dir, 'image.yaml')
+    )
+
+    run_cekit(image_dir,
+              ['-v',
+               'build',
+               'docker'])
+
+    assert "Finished!" in caplog.text
+
+
+# https://github.com/cekit/cekit/issues/533
+@pytest.mark.parametrize('parameter', ['content_sets', 'content_sets_file'])
+def test_disabling_content_sets(tmpdir, caplog, parameter):
+    image_dir = str(tmpdir.mkdir('source'))
+
+    shutil.copy2(
+        os.path.join(os.path.dirname(__file__), 'images',
+                     'image-gh-533-disable-content-sets-file.yaml'),
         os.path.join(image_dir, 'image.yaml')
     )
 
+    with open(os.path.join(image_dir, 'content_sets.yml'), 'w') as fd:
+        yaml.dump({'x86_64': ['rhel-server-rhscl-7-rpms', 'rhel-7-server-rpms']},
+                  fd, default_flow_style=False)
+
     run_cekit(image_dir,
               ['-v',
                'build',
+               '--dry-run',
+               # Ugly, but double braces are required for 'format to work'
+               '--overrides', '{{"packages": {{"{0}": ~}}}}'.format(parameter),
                'docker'])
 
+    with open(os.path.join(image_dir, 'target', 'image.yaml'), 'r') as file_:
+        effective_image = yaml.safe_load(file_)
+
+    assert 'content_sets' not in effective_image['packages']
     assert "Finished!" in caplog.text