components/ruby/puppet/files/solaris/lib/puppet/provider/evs/solaris.rb
author Sungmin Lee <sungmin.lee@oracle.com>
Tue, 18 Aug 2015 15:07:30 -0700
changeset 4794 be62c55aa235
child 4801 c249904bb056
permissions -rw-r--r--
PSARC/2015/218 Add EVS support to Puppet 18043918 Add EVS support to Puppet

#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#

#
# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
#

Puppet::Type.type(:evs).provide(:evs) do
    desc "Provider for managing EVS setup in the Solaris OS"
    confine :operatingsystem => [:solaris]
    defaultfor :osfamily => :solaris, :kernelrelease => ["5.11", "5.12"]
    commands :evsadm => "/usr/sbin/evsadm"

    mk_resource_methods

    def initialize(value={})
        super(value)
        @property_flush = {}
    end

    def self.get_evs_list
        begin
            evs_list = evsadm("show-evs", "-c", "-o", "evs,tenant,status")
                .split("\n")
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "Unable to populate EVS instances: \n" \
                "#{e.inspect}"
        end
        evs_list
    end

    def self.get_evs_properties(evs, tenant, status, ensure_val)
        evs_properties = {}
        evs_fullname = tenant + "/" + evs

        evs_properties[:name] = evs_fullname
        evs_properties[:status] = status 
        evs_properties[:ensure] = ensure_val
        
        evsadm("show-evsprop", "-f", "tenant=#{tenant}", "-c", "-o", 
            "property,value", evs).split("\n").collect do |each_evsprop|
            property, value = each_evsprop.split(":")
            value = "" if value.nil?
            case property
            # read/write properties (always updatable)
            when "maxbw"
                evs_properties[:maxbw] = value
            when "priority"
                evs_properties[:priority] = value
            when "protection"
                evs_properties[:protection] = value
            # read-only properties (settable upon cration)
            when "l2-type"
                evs_properties[:l2_type] = value
            when "vlanid"
                evs_properties[:vlanid] = value
            when "vni"
                evs_properties[:vni] = value
            when "uuid"
                evs_properties[:uuid] = value
            end
        end
        
        Puppet.debug "EVS Properties: #{evs_properties.inspect}"
        evs_properties
    end
    
    def self.instances
        get_evs_list.collect do |each_evs|
            evs, tenant, status = each_evs.strip.split(":")
            evs_properties = get_evs_properties(evs, tenant, status, :present)
            new(evs_properties) # Create a provider instance
        end
    end

    def self.prefetch(resources)
        instances.each do |inst|
            if resource = resources[inst.name]
                resource.provider = inst
            end
        end
    end
    
    def exists?
        @property_hash[:ensure] == :present
    end

    def create
        tenant, evs = get_tenant_and_evs_name
        begin
            create_evs(tenant, evs, add_properties(@resource))
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "Cannot create EVS: \n#{e.inspect}"
        end
    end

    def destroy
        tenant, evs = get_tenant_and_evs_name
        begin
            delete_evs(tenant, evs)
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "Cannot delete EVS: \n#{e.inspect}"
        end
    end

    ### Define Setters ###
    ## read/write properties (always updatable) ##
    def maxbw=(value)
        @property_flush[:maxbw] = value
    end

    def priority=(value)
        @property_flush[:priority] = value
    end
    
    def protection=(value)
        @property_flush[:protection] = value
    end
    
    ## read-only properties (settable upon creation) ##
    def l2_type=(value)
        raise Puppet::Error, "l2_type property is settable only upon creation"
    end
    
    def vlanid=(value)
        raise Puppet::Error, "valid property is settable only upon creation"
    end
    
    def vni=(value)
        raise Puppet::Error, "vni property is settable only upon creation"
    end
    
    def uuid=(value)
        raise Puppet::Error, "uuid property is settable only upon creation"
    end
   
    # Create EVS instance
    def create_evs(tenant, evs, properties)
        begin
            evsadm("create-evs", "-T", tenant, properties, evs)
        rescue Puppet::ExecutionFailure => e
            # Pass up the exception to upper level
            raise
        end
    end

    # Destroy EVS instance
    def delete_evs(tenant, evs)
        begin
            evsadm("delete-evs", "-T", tenant, evs)
        rescue Puppet::ExecutionFailure => e
            # Pass up the exception to upper level
            raise
        end
    end
    
    # Set read/write property of EVS instance
    def set_evsprop(tenant, evs, property)
        begin
            evsadm("set-evsprop", "-T", tenant, property, evs)
        rescue Puppet::ExecutionFailure => e
            # Pass up the exception to upper level
            raise
        end
    end

    # Parse the "name" value from user and yield tenant and EVS instance name
    def get_tenant_and_evs_name()
        usrstr = @resource[:name].split("/")
        if usrstr.length == 2
            return usrstr[0], usrstr[1]
        else
            raise Puppet::Error, "Invalid EVS name #{@resource[:name]} \n" \
                "Name convention must be <tenant>/<evs>"
        end 
    end
    
    # property setter for EVS creation
    def add_properties(source)
        p = []
        prop_list = {
            "maxbw" => source[:maxbw], 
            "priority" => source[:priority],
            "protection" => source[:protection],
            "l2-type" => source[:l2_type],
            "vlanid" => source[:vlanid],
            "vni" => source[:vni],
            "uuid" => source[:uuid]
            }
        prop_list.each do |key, value|
            next if (value == nil) || (value == "")
            p << "#{key}=#{value}"
        end
        return [] if p.empty?
        properties = Array["-p", p.join(",")]
    end

    # Update property change
    def flush
        tenant, evs = get_tenant_and_evs_name

        # Update property values when specified
        unless @property_flush.empty?
            # update multiple property values iteratively
            @property_flush.each do |key, value|
                prop = ["-p", "#{key}=#{value}"]
                begin 
                    set_evsprop(tenant, evs, prop)
                rescue Puppet::ExecutionFailure => e
                    raise Puppet::Error, "Cannot update the property " \
                        "#{key}=#{value}.\n#{e.inspect}"
                end
            end
        end
        # Synchronize all the SHOULD values to IS values
        @property_hash = resource.to_hash
    end
end