// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#ifndef __TEST_DOCKER_ARCHIVE_HPP__
#define __TEST_DOCKER_ARCHIVE_HPP__

#include <process/collect.hpp>
#include <process/future.hpp>
#include <process/owned.hpp>

#include <stout/error.hpp>
#include <stout/json.hpp>
#include <stout/jsonify.hpp>
#include <stout/nothing.hpp>
#include <stout/os.hpp>
#include <stout/path.hpp>
#include <stout/stringify.hpp>
#include <stout/try.hpp>

#include "common/command_utils.hpp"

#include "tests/containerizer/rootfs.hpp"

using process::Failure;
using process::Future;

namespace mesos {
namespace internal {
namespace tests {

// This represents a docker archive. It has the same format
// as that tarball generated by doing a 'docker save'.
class DockerArchive
{
public:
  // Create a docker test image tarball in docker registry directory.
  // Users can define own entrypoint/cmd as JSON array of JSON string
  // (e.g., `[\"sh\", \"-c\"]`).
  //
  // NOTE: The default value for `environment` includes some environment
  // variables which will cause problems if they are fed into one of Mesos'
  // built-in executors. This is on purpose, as the environment variables
  // of the image should not be passed into built-in executors. Tests that
  // use a custom executor should consider overriding this default.
  static Future<Nothing> create(
      const std::string& directory,
      const std::string& name,
      const std::string& entrypoint = "null",
      const std::string& cmd = "null",
      const std::vector<std::string>& environment = {
        {"LD_LIBRARY_PATH=invalid"},
        {"LIBPROCESS_IP=invalid"},
        {"LIBPROCESS_PORT=invalid"}})
  {
    Try<Nothing> mkdir = os::mkdir(directory, true);
    if (mkdir.isError()) {
      return Failure("Failed to create '" + directory + "': " + mkdir.error());
    }

    const std::string imagePath = path::join(directory, name);

    mkdir = os::mkdir(imagePath);
    if (mkdir.isError()) {
      return Failure("Failed to create docker test image directory '" +
                     imagePath + "': " + mkdir.error());
    }

    const std::string layerId =
      "815b809d588c80fd6ddf4d6ac244ad1c01ae4cbe0f91cc7480e306671ee9c346";

    const std::string layerPath = path::join(imagePath, layerId);

    // Create docker test image `repositories`.
    JSON::Value repositories = JSON::parse(strings::format(
        R"~(
        {
            "%s": {
                "latest": "%s"
            }
        })~",
        name,
        layerId).get()).get();

    Try<Nothing> write = os::write(
        path::join(imagePath, "repositories"),
        stringify(repositories));

    if (write.isError()) {
      return Failure("Failed to save docker test image 'repositories': " +
                     write.error());
    }

    mkdir = os::mkdir(layerPath);
    if (mkdir.isError()) {
      return Failure("Failed to create docker test image layer '" +
                     layerId + "': " + mkdir.error());
    }

    JSON::Value manifest = JSON::parse(strings::format(
        R"~(
        {
            "id": "815b809d588c80fd6ddf4d6ac244ad1c01ae4cbe0f91cc7480e306671ee9c346",
            "created": "2016-03-02T17:16:00.167415955Z",
            "container": "eb53609036555d26c39bdccfa9850426934bdfde96111d099041689b2251a377",
            "container_config": {
                "Hostname": "eb5360903655",
                "Domainname": "",
                "User": "",
                "AttachStdin": false,
                "AttachStdout": false,
                "AttachStderr": false,
                "Tty": false,
                "OpenStdin": false,
                "StdinOnce": false,
                "Env": null,
                "Cmd": [
                    "/bin/sh",
                    "-c",
                    "#(nop) ADD file:81ba6f20bdb99e6c13c434a577069860b6656908031162083b1ac9c02c71dd9f in /"
                ],
                "Image": "",
                "Volumes": null,
                "WorkingDir": "",
                "Entrypoint": null,
                "OnBuild": null,
                "Labels": null
            },
            "docker_version": "1.9.1",
            "config": {
                "Hostname": "eb5360903655",
                "Domainname": "",
                "User": "",
                "AttachStdin": false,
                "AttachStdout": false,
                "AttachStderr": false,
                "Tty": false,
                "OpenStdin": false,
                "StdinOnce": false,
                "Env": %s,
                "Cmd": %s,
                "Image": "",
                "Volumes": null,
                "WorkingDir": "",
                "Entrypoint": %s,
                "OnBuild": null,
                "Labels": null
            },
            "architecture": "amd64",
            "os": "linux"
        })~",
        std::string(jsonify(environment)),
        cmd,
        entrypoint).get()).get();

    write = os::write(
        path::join(layerPath, "json"),
        stringify(manifest));

    if (write.isError()) {
      return Failure("Failed to save docker test image layer '" + layerId +
                     "': " + write.error());
    }

    const std::string rootfsDir = path::join(layerPath, "layer");

    mkdir = os::mkdir(rootfsDir);
    if (mkdir.isError()) {
      return Failure("Failed to create layer rootfs directory '" +
                     rootfsDir + "': " + mkdir.error());
    }

    // Create one linux rootfs for the layer.
    Try<process::Owned<Rootfs>> rootfs = LinuxRootfs::create(rootfsDir);
    if (rootfs.isError()) {
      return Failure("Failed to create docker test image rootfs: " +
                     rootfs.error());
    }

    Future<Nothing> tarRootfs = command::tar(
        Path("."),
        Path(path::join(layerPath, "layer.tar")),
        rootfsDir);

    tarRootfs.await();

    if (!tarRootfs.isReady()) {
      return Failure(
          "Failed to tar root filesystem: " +
          (tarRootfs.isFailed() ? tarRootfs.failure() : "discarded"));
    }

    Try<Nothing> rmdir = os::rmdir(rootfsDir);
    if (rmdir.isError()) {
        return Failure("Failed to remove layer rootfs directory: " +
                       rmdir.error());
    }

    write = os::write(
        path::join(layerPath, "VERSION"),
        "1.0");

    if (write.isError()) {
      return Failure("Failed to save layer version: " + write.error());
    }

    Future<Nothing> tarImage = command::tar(
        Path("."),
        Path(path::join(directory, name + ".tar")),
        imagePath);

    tarImage.await();

    if (!tarImage.isReady()) {
      return Failure(
          "Failed to tar docker test image: " +
          (tarImage.isFailed() ? tarImage.failure() : "discarded"));
    }

    rmdir = os::rmdir(imagePath);
    if (rmdir.isError()) {
      return Failure("Failed to remove image directory: " +
                     rmdir.error());
    }

    return Nothing();
  }
};

} // namespace tests {
} // namespace internal {
} // namespace mesos {

#endif // __TEST_DOCKER_ARCHIVE_HPP__
