AUTHOR
FIREWHEEL Team
DONE
DESCRIPTION

Push a file to a VM using the VM resource handler. This does not require that
the VM is running a SSH server. Also, unlike :ref:`helper_scp`, there is no need
to use the :ref:`control_network_mc` model component since the VM resource handler has access to
the VM through a serial port.

All files get placed at the location specified on the command line.

.. note::

    The destination **MUST** be the full path (including the filename), not simply a destination directory.

.. warning::

    Any shell expansions (e.g. ``~``) used in the ``destination`` path are resolved **BEFORE** the file is pushed to the VM.


**Usage:**  ``firewheel push file [-h] <filename> <vm hostname> <destination>``

Arguments
+++++++++

Named Arguments
^^^^^^^^^^^^^^^

.. option:: -h, --help

    Show this help message and exit

Positional Arguments
^^^^^^^^^^^^^^^^^^^^

.. option:: <filename>

    The name of the file to push to the VM

.. option:: <vm hostname>

    The hostname of the VM to push the file to.

.. option:: <destination>

    The full path (including the filename) of the destination location on the VM for the file.

Example
+++++++

``firewheel push file /tmp/test.txt host.root.net /tmp/myfile.txt``

``firewheel push file /tmp/test.txt whost.root.net '/Users/User/Downloads/myfile.txt'``

DONE
RUN LocalPython ON control
#!/usr/bin/env python

import sys
import pickle
import argparse
from pathlib import Path, PureWindowsPath

import firewheel.vm_resource_manager.api as vrm_api
from firewheel.lib.minimega.api import minimegaAPI
from firewheel.vm_resource_manager.schedule_db import ScheduleDb
from firewheel.vm_resource_manager.schedule_entry import ScheduleEntry


def handle_schedule_entry(name, file_name, destination, windows):
    """Handle the scheduling of a VM resource file transfer.

    This function retrieves the schedule for a specified virtual machine (VM)
    from the schedule database, adds a new schedule entry for transferring a
    resource file to the VM, and updates the schedule in the database. It
    supports both Unix-like and Windows file transfer commands.

    Args:
        name (str): The name of the VM for which the schedule is being handled.
        file_name (str): The name of the resource file to be transferred.
        destination (str): The destination path on the VM where the file will be transferred.
        windows (bool): A flag indicating whether the destination is a Windows environment.
    """
    schedule_db = ScheduleDb()
    pickled_schedule = schedule_db.get(name)
    if not pickled_schedule:
        print(f"Unable to get schedule for VM: {name}")
        sys.exit(1)
    schedule = pickle.loads(pickled_schedule)

    print(f"Adding '{file_name}' as a VM Resource.")
    se = ScheduleEntry(-100000, ignore_failure=True)
    vrm_api.add_vm_resource_file(file_name)
    file_name = Path(file_name).name
    if not windows:
        print(f"Going to transfer '{Path(file_name)}' to destination "
              f"'{Path(destination)}' on VM '{name}'.\n")
        se.set_executable("mv", f"{file_name} {destination}")
    else:
        print(f"Going to transfer '{Path(file_name)}' to destination "
              f"'{PureWindowsPath(destination)}' on VM '{name}'.\n")
        se.set_executable("move", f"{file_name} {destination}")
    se.add_file(file_name, file_name, False)
    schedule.append(se)
    schedule_db.put(name, pickle.dumps(schedule), None)
    print(
        "Successfully added a new schedule entry. "
        "Pending any errors, the file will be added shortly. "
        "To investigate the progress, visit the VM's resource log file."
    )


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Push a file to a VM using the VM resource handler.",
        prog="firewheel push file",
    )

    parser.add_argument(
        "filename",
        help="The path to the file to push to the VM.",
    )

    parser.add_argument(
        "vm_name",
        help="The hostname of the VM to push the file to.",
    )

    parser.add_argument(
        "destination",
        help="The full path (including the filename) of the destination "
             "location on the VM for the file.",
    )

    args = parser.parse_args()

    if not Path(args.filename).exists():
        raise FileNotFoundError(f"The file being pushed to the VM "
                                f"'{Path(args.filename)}' does not exist!")

    mm_api = minimegaAPI()
    mm_dict = mm_api.mm_vms()
    windows_vm = False
    try:
        if "windows" in mm_dict[args.vm_name]["image"]:
            windows_vm = True
    except KeyError:
        print(f"No VM '{args.vm_name}' found.")
        sys.exit(1)

    handle_schedule_entry(args.vm_name, args.filename, args.destination,
                          windows_vm)
DONE
