components/ruby/puppet-modules/oracle-solaris_providers/files/etc/puppet/modules/solaris_providers/lib/puppet/provider/evs_vport/solaris.rb
author Shawn Ferry <shawn.ferry@oracle.com>
Wed, 10 Feb 2016 22:10:43 -0500
changeset 5438 c068f8c677e8
parent 4794 components/ruby/puppet/files/solaris/lib/puppet/provider/evs_vport/solaris.rb@be62c55aa235
permissions -rw-r--r--
PSARC/2016/016 Rename/Refactor Puppet and Puppet Module Packages 21041932 puppet, facter, and hiera need to build Ruby 2.1 packages 21042030 puppet, facter, and hiera need to stop building Ruby 1.9 packages 21613616 oracle-solaris_provider builds should come from the github repo we publish 22047789 puppet package name and dependencies are confusing 22301978 Overzealous use of $(RUBY_VERSION) in puppet packaging 22347610 GIT repos cannot be used as described in docs 22664785 Puppet module files should be owned by puppet 22675056 git clone could use --depth 1

#
# 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_vport).provide(:evs_vport) do
    desc "Provider for managing EVS VPort 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_vport_list
        begin
            vport_list = evsadm("show-vport", "-c", "-o", 
                "name,tenant,status").split("\n")
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "unable to populate VPort instances: \n" \
                "#{e.inspect}"
            return nil
        end
        vport_list
    end
   
    def self.get_vport_properties(vport, tenant, status, ensure_val)
        vport_props = {}
        vport_fullname = tenant + "/" + vport
        vport_props[:name] = vport_fullname
        vport_props[:status] = status
        vport_props[:ensure] = ensure_val
        
        evsadm("show-vportprop", "-f", "tenant=#{tenant}", "-c", "-o",
            "property,value", vport).split("\n").collect do |each_prop|
            property, value = each_prop.split(":", 2)
            value = "" if value.nil?
            case property
            # read/write properties (always updatable)
            when "cos"
                vport_props[:cos] = value
            when "maxbw"
                vport_props[:maxbw] = value
            when "priority"
                vport_props[:priority] = value
            when "protection"
                vport_props[:protection] = value
            # read-only properties (settable upon creation)
            when "ipaddr"
                vport_props[:ipaddr] = value
            when "macaddr"
                # macaddr ":" appears to be "\:". change it to ":"
                vport_props[:macaddr] = value.gsub! "\\:", ":"
            when "uuid"
                vport_props[:uuid] = value
            end
        end

        Puppet.debug "VPort properties: #{vport_props.inspect}"
        vport_props
    end

    def self.instances
        get_vport_list.collect do |each_vport|
            vport, tenant, status = each_vport.strip.split(":")
            vport_props = get_vport_properties(vport, tenant, status, :present)
            new(vport_props) # 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, vport = get_tenant_and_vport_name
        begin
            create_vport(tenant, vport, add_properties(@resource))
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "Cannot add VPort: \n #{e.inspect}"
        end
    end

    def destroy
        tenant, vport = get_tenant_and_vport_name
        begin
            delete_vport(tenant, vport)
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "Cannot remove VPort: \n #{e.inspect}"
        end
    end

    def reset
        tenant, vport = get_tenant_and_vport_name
        begin
            evsadm("reset-vport", "-T", tenant, vport)
        rescue Puppet::ExecutionFailure => e
            raise Puppet::Error, "Cannot reset VPort: \n #{e.inspect}"
        end

        @resource[:ensure] = :present
        Puppet::notice "The VPort has been successfully reset."
    end
    
    ### Define Setters ###
    ## read/write properties (always updatable) ##
    def cos=(value)
        @property_flush[:cos] = value
    end

    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 ipaddr=(value)
        raise Puppet::Error, "ipaddr property is settable only upon creation"
    end

    def macaddr=(value)
        raise Puppet::Error, "macaddr property is settable only upon creation"
    end

    def uuid=(value)
        raise Puppet::Error, "uuid property is settable only upon creation"
    end

    # Add VPort Instance
    def create_vport(tenant, vport, properties)
        begin
            evsadm("add-vport", "-T", tenant, properties, vport)
        rescue Puppet::ExecutionFailure => e
            # Pass up the exception to upper level
            raise
        end
    end

    # Remove Vport Instance
    def delete_vport(tenant, vport)
        begin
            evsadm("remove-vport", "-T", tenant, vport)
        rescue Puppet::ExecutionFailure => e
            # Pass up the exception to upper level
            raise
        end
    end
    
    # set read/write property 
    def set_vportprop(tenant, vport, property)
        begin
            evsadm("set-vportprop", "-T", tenant, property, vport)
        rescue Puppet::ExecutionFailure => e
            # Pass up the exception to upper level
            raise
        end
    end

    # Parse the "name" value from user and yield tenant and vport name
    def get_tenant_and_vport_name
        fullname = @resource[:name]

        return [] if fullname == nil
        parsed_val = fullname.strip.split("/")
        if (parsed_val.length != 3)
            raise Puppet::Error, "Invalid VPort name #{@resource[:name]} \n" \
                "Name convention must be <tenant>/<evs>/<vport>"
        end
        tenant, evs, vport = parsed_val
        return tenant, evs + "/" + vport
    end

    # property setter for vport creation
    def add_properties(source)
        p = []
        if source[:ipaddr] != nil
            source[:ipaddr] = source[:ipaddr].split('/')[0]
        end
        prop_list = {
            "cos" => source[:cos], 
            "maxbw" => source[:maxbw], 
            "priority" => source[:priority],
            "protection" => source[:protection],
            "ipaddr" => source[:ipaddr],
            "macaddr" => source[:macaddr],
            "uuid" => source[:uuid]
        }
        prop_list.each do |key, value|
            next if (value == "") || (value == nil)
            p << "#{key}=#{value}"
        end
        return [] if p.empty?
        properties = Array["-p", p.join(",")]
    end

    # Update property change
    def flush
        tenant, vport = get_tenant_and_vport_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_vportprop(tenant, vport, 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