<commit_before>#
# Author:: <NAME> <<EMAIL>>
#
# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# 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.
#

begin
  require 'net/netconf/jnpr'
  require 'net/netconf/jnpr/ioproc'
  require 'junos-ez/stdlib'
rescue LoadError
  msg  = "Could not load the junos-ez-stdlib gem..."
  msg << "ensure you are using the Chef for Junos packages"
  Chef::Log.debug msg
end

module Netdev
  class JunosApiClient

    begin
      # All possible resources `junos-ez-stdlib`
      # is able to manage. This Hash is used for
      # validation and metaprogramming.
      KNOWN_RESOURCES = {
        :l1_ports => Junos::Ez::L1ports,
        :l2_ports => Junos::Ez::L2ports,
        :ip_ports => Junos::Ez::IPports,
        :vlans => Junos::Ez::Vlans,
        :lag_ports => Junos::Ez::LAGports
      }
    rescue NameError
      # If the requires above didn't work our class
      # references are definetly not going to work!
    end

    # The `Junos::Ez` providers expect certain values
    # to be symbolized or requests will fail.
    VALUES_TO_SYMBOLIZE = %w{ auto up down half full }

    attr_reader :resource_type
    attr_reader :resource_name

    def initialize(resource_type, resource_name)

      unless KNOWN_RESOURCES.keys.include?(resource_type)
        error_message  = "Invalid resource type :#{resource_type}."
        error_message << " Try one of: :#{KNOWN_RESOURCES.keys.join(", :")}"
        raise error_message
      end

      @resource_type = resource_type
      @resource_name = resource_name
    end

    # STAND BACK...IT'S METAPROGRAMMING TIME
    KNOWN_RESOURCES.each_pair do |resource, provider_module|

      # Create a child class for each logical resource type. This forces
      # us to be explicit on which type of resource to manage.
      c = Class.new(self)
      c.class_eval <<-EVAL
        def initialize(resource_name)
          super(:#{resource}, resource_name)
        end
      EVAL

      class_name = provider_module.to_s.split("::").last
      self.const_set class_name, c
    end

    # Writes pending configuration and commits the change.
    def write!
      with_safe_commit do
        managed_resource.write!
        Chef::Log.debug("#{self.to_s} wrote and committed configuration changes")
      end
    end

    # Removes managed resource and commits the change.
    def delete!
      with_safe_commit do
        managed_resource.delete!
        Chef::Log.debug("#{self.to_s} deleted resource")
      end
    end

    # Activate managed resource and commits the change.
    def activate!
      with_safe_commit do
        managed_resource.activate!
        Chef::Log.debug("#{self.to_s} activated resource")
      end
    end

    # Deactivate managed resource and commits the change.
    def deactivate!
      with_safe_commit do
        managed_resource.deactivate!
        Chef::Log.debug("#{self.to_s} deactivated resource")
      end
    end

    # Given a hash of new property values and old property values
    # determines which have changed. `nil` values are ignored.
    #
    # @param new_values [#Hash<Symbol, Object>]
    # @param current_values [#Hash<Symbol, Object>]
    #
    # @return [#Hash<Symbol, Object>] updated properties
    def updated_changed_properties(new_values, current_values)
      new_values.each_pair do |property_name, new_value|
        old_value = current_values[property_name]

        if !new_value.nil? && (old_value != new_value)
          Chef::Log.debug("#{self.to_s} property '#{property_name}' has changed to '#{new_value}'")

          if managed_resource.properties.include?(property_name)
            # junos-ez-stdlib prefers some values as symbols
            managed_resource[property_name] = if VALUES_TO_SYMBOLIZE.include?(new_value)
                                                new_value.to_sym
                                              else
                                                new_value
                                              end
          else
            error_message  = "#{self.to_s} don't know how to manage property :#{property_name}."
            error_message << " Known properties include: :#{managed_resource.properties.keys.join(", :")}"
            raise error_message
          end
        end
      end
      # return Hash of updated properties
      managed_resource.should
    end

    def managed_resource
      @managed_resource ||= transport.send(resource_type)[resource_name]
    end

    def to_s
      "#{self.class.to_s}[#{resource_name}]"
    end

    protected

    # Creates a fully-intialized Netconf transport instance for
    # communicating with the Junos XML API. Currently we only support
    # the `IOProc` transport which means this client must be run from
    # the switch it is managing.
    #
    # @return [Netconf::Junos::IOProc] intialized transport instance
    def transport
      @transport || begin
        # Create a connection to the NETCONF service
        transport = Netconf::IOProc.new
        transport.open

        # enable basic Junos EZ Stdlib providers
        Junos::Ez::Provider(transport)
        Junos::Ez::Config::Utils(transport, :config)

        # enable provider for resource type we are managing
        provider_module = KNOWN_RESOURCES[resource_type]
        provider_module.send(:Provider, transport, resource_type)

        transport
      end
    end

    # If processing the block of code passed in is successful config<commit_msg>`||=` to properly lazily-initialize transport<commit_after>#
# Author:: <NAME> <<EMAIL>>
#
# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# 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.
#

begin
  require 'net/netconf/jnpr'
  require 'net/netconf/jnpr/ioproc'
  require 'junos-ez/stdlib'
rescue LoadError
  msg  = "Could not load the junos-ez-stdlib gem..."
  msg << "ensure you are using the Chef for Junos packages"
  Chef::Log.debug msg
end

module Netdev
  class JunosApiClient

    begin
      # All possible resources `junos-ez-stdlib`
      # is able to manage. This Hash is used for
      # validation and metaprogramming.
      KNOWN_RESOURCES = {
        :l1_ports => Junos::Ez::L1ports,
        :l2_ports => Junos::Ez::L2ports,
        :ip_ports => Junos::Ez::IPports,
        :vlans => Junos::Ez::Vlans,
        :lag_ports => Junos::Ez::LAGports
      }
    rescue NameError
      # If the requires above didn't work our class
      # references are definetly not going to work!
    end

    # The `Junos::Ez` providers expect certain values
    # to be symbolized or requests will fail.
    VALUES_TO_SYMBOLIZE = %w{ auto up down half full }

    attr_reader :resource_type
    attr_reader :resource_name

    def initialize(resource_type, resource_name)

      unless KNOWN_RESOURCES.keys.include?(resource_type)
        error_message  = "Invalid resource type :#{resource_type}."
        error_message << " Try one of: :#{KNOWN_RESOURCES.keys.join(", :")}"
        raise error_message
      end

      @resource_type = resource_type
      @resource_name = resource_name
    end

    # STAND BACK...IT'S METAPROGRAMMING TIME
    KNOWN_RESOURCES.each_pair do |resource, provider_module|

      # Create a child class for each logical resource type. This forces
      # us to be explicit on which type of resource to manage.
      c = Class.new(self)
      c.class_eval <<-EVAL
        def initialize(resource_name)
          super(:#{resource}, resource_name)
        end
      EVAL

      class_name = provider_module.to_s.split("::").last
      self.const_set class_name, c
    end

    # Writes pending configuration and commits the change.
    def write!
      with_safe_commit do
        managed_resource.write!
        Chef::Log.debug("#{self.to_s} wrote and committed configuration changes")
      end
    end

    # Removes managed resource and commits the change.
    def delete!
      with_safe_commit do
        managed_resource.delete!
        Chef::Log.debug("#{self.to_s} deleted resource")
      end
    end

    # Activate managed resource and commits the change.
    def activate!
      with_safe_commit do
        managed_resource.activate!
        Chef::Log.debug("#{self.to_s} activated resource")
      end
    end

    # Deactivate managed resource and commits the change.
    def deactivate!
      with_safe_commit do
        managed_resource.deactivate!
        Chef::Log.debug("#{self.to_s} deactivated resource")
      end
    end

    # Given a hash of new property values and old property values
    # determines which have changed. `nil` values are ignored.
    #
    # @param new_values [#Hash<Symbol, Object>]
    # @param current_values [#Hash<Symbol, Object>]
    #
    # @return [#Hash<Symbol, Object>] updated properties
    def updated_changed_properties(new_values, current_values)
      new_values.each_pair do |property_name, new_value|
        old_value = current_values[property_name]

        if !new_value.nil? && (old_value != new_value)
          Chef::Log.debug("#{self.to_s} property '#{property_name}' has changed to '#{new_value}'")

          if managed_resource.properties.include?(property_name)
            # junos-ez-stdlib prefers some values as symbols
            managed_resource[property_name] = if VALUES_TO_SYMBOLIZE.include?(new_value)
                                                new_value.to_sym
                                              else
                                                new_value
                                              end
          else
            error_message  = "#{self.to_s} don't know how to manage property :#{property_name}."
            error_message << " Known properties include: :#{managed_resource.properties.keys.join(", :")}"
            raise error_message
          end
        end
      end
      # return Hash of updated properties
      managed_resource.should
    end

    def managed_resource
      @managed_resource ||= transport.send(resource_type)[resource_name]
    end

    def to_s
      "#{self.class.to_s}[#{resource_name}]"
    end

    protected

    # Creates a fully-intialized Netconf transport instance for
    # communicating with the Junos XML API. Currently we only support
    # the `IOProc` transport which means this client must be run from
    # the switch it is managing.
    #
    # @return [Netconf::Junos::IOProc] intialized transport instance
    def transport
      @transport ||= begin
        # Create a connection to the NETCONF service
        transport = Netconf::IOProc.new
        transport.open

        # enable basic Junos EZ Stdlib providers
        Junos::Ez::Provider(transport)
        Junos::Ez::Config::Utils(transport, :config)

        # enable provider for resource type we are managing
        provider_module = KNOWN_RESOURCES[resource_type]
        provider_module.send(:Provider, transport, resource_type)

        transport
      end
    end

    # If processing the block of code passed in is successful config
{'fraction_non_alphanumeric': 0.08349256459250644, 'fraction_numerical': 0.002326161003572319, 'mean_word_length': 2.553128689492326, 'pattern_counts': {'":': 2, '<': 31, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4306585', 'n_tokens_mistral': 3437, 'n_tokens_neox': 3306, 'n_words': 1059}