#!/usr/bin/env ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)             #
#                                                                            #
# Licensed 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.                                             #
#--------------------------------------------------------------------------- #

ONE_LOCATION=ENV["ONE_LOCATION"]

if !ONE_LOCATION
    RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
    RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
end

$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+"/cli"

require 'command_parser'
require 'one_helper/oneuser_helper'

cmd=CommandParser::CmdParser.new(ARGV) do
    usage "`oneuser` <command> [<args>] [<options>]"
    version OpenNebulaHelper::ONE_VERSION

    ########################################################################
    # Global Options
    ########################################################################
    set :option, CommandParser::OPTIONS

    list_options = CLIHelper::OPTIONS
    list_options << OpenNebulaHelper::XML
    list_options << OpenNebulaHelper::NUMERIC

    READ_FILE={
        :name => "read_file",
        :short => "-r",
        :large => "--read-file",
        :description => "Read password from file"
    }

    PLAIN={
        :name => "plain",
        :short => "-p",
        :large => "--plain",
        :description => "Store plain password"
    }

    SSH={
        :name => "ssh",
        :large => "--ssh",
        :description => "SSH Auth system"
    }

    X509={
        :name => "x509",
        :large => "--x509",
        :description => "x509 Auth system for x509 certificates"
    }

    X509_PROXY={
        :name => "x509_proxy",
        :large => "--x509_proxy",
        :description => "x509 Auth system based on x509 proxy certificates"
    }

    KEY={
        :name => "key",
        :short => "-k path_to_private_key_pem",
        :large => "--key path_to_private_key_pem",
        :format => String,
        :description => "Path to the Private Key of the User"
    }

    CERT={
        :name => "cert",
        :short => "-c path_to_user_cert_pem",
        :large => "--cert path_to_user_cert_pem",
        :format => String,
        :description => "Path to the Certificate of the User"
    }

    PROXY={
        :name => "proxy",
        :large => "--proxy path_to_user_proxy_pem",
        :format => String,
        :description => "Path to the user proxy certificate"
    }

    TIME={
        :name  => "time",
        :large => "--time x",
        :format => Integer,
        :description => "Token duration in seconds, defaults to 3600 (1 h)"
    }

    create_options = [READ_FILE, PLAIN, SSH, X509, KEY, CERT]
    login_options  = [SSH, X509, X509_PROXY, KEY, CERT, PROXY, TIME]

    ########################################################################
    # Formatters for arguments
    ########################################################################
    set :format, :groupid, OpenNebulaHelper.rname_to_id_desc("GROUP") do |arg|
        OpenNebulaHelper.rname_to_id(arg, "GROUP")
    end

    set :format, :userid, OneUserHelper.to_id_desc do |arg|
        helper = OneUserHelper.new
        helper.to_id(arg)
    end

    set :format, :userid_list, OneUserHelper.list_to_id_desc do |arg|
        helper = OneUserHelper.new
        helper.list_to_id(arg)
    end

    set :format, :password, OneUserHelper.password_to_str_desc do |arg|
        OneUserHelper.password_to_str(arg, options)
    end

    ########################################################################
    # Commands
    ########################################################################

    create_desc = <<-EOT.unindent
        Creates a new User
        Examples:
          oneuser create my_user my_password
          oneuser create my_user /tmp/mypass -r
          oneuser create my_user --ssh --key /tmp/id_rsa
          oneuser create my_user --ssh -r /tmp/public_key
          oneuser create my_user --x509 --cert /tmp/my_cert.pem
    EOT

    command :create, create_desc, :username, [:password, nil],
            :options=>create_options do
        helper = OneUserHelper.new

        if args[1]
            pass = args[1]
        else
            rc = helper.password(options)
            if rc.first == 0
                pass = rc[1]
            else
                exit_with_code *rc
            end
        end

        helper.create_resource(options) do |user|
            user.allocate(args[0], pass)
        end
    end

    login_desc = <<-EOT.unindent
        Creates the Login token for authentication
        Examples:
          oneuser login my_user --ssh --key /tmp/id_rsa --time 72000
          oneuser login my_user --x509 --cert /tmp/my_cert.pem \
                                --key /tmp/my_key.pk --time 72000
          oneuser login my_user --x509_proxy --proxy /tmp/my_cert.pem \
                                --time 72000
    EOT

    command :login, login_desc, :username, :options=>login_options do
        OneUserHelper.login(args[0], options)
    end

    key_desc = <<-EOT.unindent
        Shows a public key from a private SSH key. Use it as password
        for the SSH authentication mechanism.
    EOT

    command :key, key_desc, :options=>[KEY] do
        require 'ssh_auth'

        options[:key] ||= ENV['HOME']+'/.ssh/id_rsa'

        begin
            sshauth = SshAuth.new(:private_key=>options[:key])
        rescue Exception => e
            exit_with_code -1, e.message
        end

        puts sshauth.public_key
        exit_with_code 0
    end


    delete_desc = <<-EOT.unindent
        Deletes the given User
    EOT

    command :delete, delete_desc, [:range, :userid_list] do
        helper = OneUserHelper.new
        helper.perform_actions(args[0],options,"deleted") do |user|
            user.delete
        end
    end

    passwd_desc = <<-EOT.unindent
        Changes the given User's password
    EOT

    command :passwd, passwd_desc, :userid, [:password, nil],
            :options=>create_options do
        helper = OneUserHelper.new

        if args[1]
            pass = args[1]
        else
            rc = helper.password(options)
            if rc.first == 0
                pass = rc[1]
            else
                exit_with_code *rc
            end
        end

        helper.perform_action(args[0],options,"Password changed") do |user|
            user.passwd(pass)
        end
    end

    chgrp_desc = <<-EOT.unindent
        Changes the User's main group
    EOT

    command :chgrp, chgrp_desc, [:range, :userid_list], :groupid do
        helper = OneUserHelper.new
        helper.perform_actions(args[0],options,"Group changed") do |user|
            user.chgrp(args[1].to_i)
        end
    end

    list_desc = <<-EOT.unindent
        Lists Users in the pool
    EOT

    command :list, list_desc, :options=>list_options do
        helper = OneUserHelper.new
        helper.list_pool(options)
    end

    show_desc = <<-EOT.unindent
        Shows information for the given User
    EOT

    command :show, show_desc, [:userid, nil],
            :options=>OpenNebulaHelper::XML do
        user=args[0] || OpenNebula::User::SELF
        helper = OneUserHelper.new
        helper.show_resource(user,options)
    end

end
