<commit_before>#!/usr/bin/env ruby
#
# October 2015, <NAME>
#
# Copyright (c) 2015-2016 Cisco and/or its affiliates.
#
# 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.

require_relative '../client'
Cisco::Client.silence_warnings do
  require 'grpc'
end
require 'json'
require_relative 'ems_services'
require_relative 'client_errors'

include IOSXRExtensibleManagabilityService
include Cisco::Logger

# Client implementation using gRPC API for IOS XR
class Cisco::Client::GRPC < Cisco::Client
  register_client(self)

  attr_accessor :timeout

  def initialize(address, username, password)
    # TODO: remove if/when we have a local socket to use
    if address.nil? && username.nil? && password.nil? && ENV['NODE']
      address ||= ENV['NODE'].split(' ')[0]
      username ||= ENV['NODE'].split(' ')[1]
      password ||= ENV['NODE'].split(' ')[2]
    end
    super(address:      address,
          username:     username,
          password:     password,
          data_formats: [:cli],
          platform:     :ios_xr)
    @config = GRPCConfigOper::Stub.new(address, :this_channel_is_insecure)
    @exec = GRPCExec::Stub.new(address, :this_channel_is_insecure)

    # Make sure we can actually connect
    @timeout = 5
    begin
      base_msg = 'gRPC client creation failure: '
      get(command: 'show clock')
    rescue Cisco::Client::ClientError => e
      error 'initial connect failed: ' + e.to_s
      if e.message[/deadline exceeded/i]
        raise Cisco::Client::ConnectionRefused, \
              base_msg + 'timed out during initial connection: ' + e.message
      end
      raise e.class, base_msg + e.message
    end

    # Let commands in general take up to 2 minutes
    @timeout = 120
  end

  def validate_args(address, username, password)
    super
    base_msg = 'gRPC client creation failure: '
    fail TypeError, base_msg + 'address must be specified' if address.nil?
    fail ArgumentError, base_msg + 'port # required in address' \
         unless address[/:/]
    # Connection to remote system - username and password are required
    fail TypeError, base_msg + 'username must be specified' if username.nil?
    fail TypeError, base_msg + 'password must be specified' if password.nil?
  end

  def cache_flush
    @cache_hash = {
      'cli_config'           => {},
      'show_cmd_text_output' => {},
      'show_cmd_json_output' => {},
    }
  end

  # Configure the given CLI command(s) on the device.
  #
  # @raise [RequestNotSupported] if this client doesn't support CLI config
  #
  # @param data_format one of Cisco::DATA_FORMATS. Default is :cli
  # @param context [Array<String>] Zero or more configuration commands used
  #                to enter the desired CLI sub-mode
  # @param values [Array<String>] One or more commands to enter within the
  #   CLI sub-mode.
  def set(data_format: :cli,
          context:     nil,
          values:      nil)
    context = munge_to_array(context)
    values = munge_to_array(values)
    super
    # IOS XR lets us concatenate submode commands together.
    # This makes it possible to guarantee we are in the correct context:
    #   context: ['foo', 'bar'], values: ['baz', 'bat']
    #   ---> values: ['foo bar baz', 'foo bar bat']
    # However, there's a special case for 'no' commands:
    #   context: ['foo', 'bar'], values: ['no baz']
    #   ---> values: ['no foo bar baz'] ---- the 'no' goes at the start
    context = context.join(' ')
    unless context.empty?
      values.map! do |cmd|
        match = cmd[/^\s*no\s+(.*)/, 1]
        if match
          cmd = "no #{context} #{match}"
        else
          cmd = "#{context} #{cmd}"
        end
        cmd
      end
    end
    # CliConfigArgs wants a newline-separated string of commands
    args = CliConfigArgs.new(cli: values.join("\n"))
    req(@config, 'cli_config', args)
  end

  def get(data_format: :cli,
          command:     nil,
          context:     nil,
          value:       nil)
    super
    fail ArgumentError if command.nil?
    args = ShowCmdArgs.new(cli: command)
    output = req(@exec, 'show_cmd_text_output', args)
    self.class.filter_cli(cli_output: output, context: context, value: value)
  end

  def req(stub, type, args)
    if cache_enable? && @cache_hash[type] && @cache_hash[type][args.cli]
      return @cache_hash[type][args.cli]
    end

    debug "Sending '#{type}' request:"
    if args.is_a?(ShowCmdArgs) || args.is_a?(CliConfigArgs)
      debug "  with cli: '#{args.cli}'"
    end
    output = Client.silence_warnings do
      response = stub.send(type, args,
                           timeout:  @timeout,
                           username: @username,
                           password: <PASSWORD>)<commit_msg>Fix NameError in Ruby 2.0<commit_after>#!/usr/bin/env ruby
#
# October 2015, <NAME>
#
# Copyright (c) 2015-2016 Cisco and/or its affiliates.
#
# 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.

require_relative '../client'
Cisco::Client.silence_warnings do
  require 'grpc'
end
require 'json'
require_relative 'ems_services'
require_relative 'client_errors'

include IOSXRExtensibleManagabilityService
include Cisco::Logger

# Client implementation using gRPC API for IOS XR
class Cisco::Client::GRPC < Cisco::Client
  register_client(self)

  attr_accessor :timeout

  def initialize(address, username, password)
    # TODO: remove if/when we have a local socket to use
    if address.nil? && username.nil? && password.nil? && ENV['NODE']
      address ||= ENV['NODE'].split(' ')[0]
      username ||= ENV['NODE'].split(' ')[1]
      password ||= ENV['NODE'].split(' ')[2]
    end
    super(address:      address,
          username:     username,
          password:     password,
          data_formats: [:cli],
          platform:     :ios_xr)
    @config = GRPCConfigOper::Stub.new(address, :this_channel_is_insecure)
    @exec = GRPCExec::Stub.new(address, :this_channel_is_insecure)

    # Make sure we can actually connect
    @timeout = 5
    begin
      base_msg = 'gRPC client creation failure: '
      get(command: 'show clock')
    rescue Cisco::Client::ClientError => e
      error 'initial connect failed: ' + e.to_s
      if e.message[/deadline exceeded/i]
        raise Cisco::Client::ConnectionRefused, \
              base_msg + 'timed out during initial connection: ' + e.message
      end
      raise e.class, base_msg + e.message
    end

    # Let commands in general take up to 2 minutes
    @timeout = 120
  end

  def validate_args(address, username, password)
    super
    base_msg = 'gRPC client creation failure: '
    fail TypeError, base_msg + 'address must be specified' if address.nil?
    fail ArgumentError, base_msg + 'port # required in address' \
         unless address[/:/]
    # Connection to remote system - username and password are required
    fail TypeError, base_msg + 'username must be specified' if username.nil?
    fail TypeError, base_msg + 'password must be specified' if password.nil?
  end

  def cache_flush
    @cache_hash = {
      'cli_config'           => {},
      'show_cmd_text_output' => {},
      'show_cmd_json_output' => {},
    }
  end

  # Configure the given CLI command(s) on the device.
  #
  # @raise [RequestNotSupported] if this client doesn't support CLI config
  #
  # @param data_format one of Cisco::DATA_FORMATS. Default is :cli
  # @param context [Array<String>] Zero or more configuration commands used
  #                to enter the desired CLI sub-mode
  # @param values [Array<String>] One or more commands to enter within the
  #   CLI sub-mode.
  def set(data_format: :cli,
          context:     nil,
          values:      nil)
    context = munge_to_array(context)
    values = munge_to_array(values)
    super
    # IOS XR lets us concatenate submode commands together.
    # This makes it possible to guarantee we are in the correct context:
    #   context: ['foo', 'bar'], values: ['baz', 'bat']
    #   ---> values: ['foo bar baz', 'foo bar bat']
    # However, there's a special case for 'no' commands:
    #   context: ['foo', 'bar'], values: ['no baz']
    #   ---> values: ['no foo bar baz'] ---- the 'no' goes at the start
    context = context.join(' ')
    unless context.empty?
      values.map! do |cmd|
        match = cmd[/^\s*no\s+(.*)/, 1]
        if match
          cmd = "no #{context} #{match}"
        else
          cmd = "#{context} #{cmd}"
        end
        cmd
      end
    end
    # CliConfigArgs wants a newline-separated string of commands
    args = CliConfigArgs.new(cli: values.join("\n"))
    req(@config, 'cli_config', args)
  end

  def get(data_format: :cli,
          command:     nil,
          context:     nil,
          value:       nil)
    super
    fail ArgumentError if command.nil?
    args = ShowCmdArgs.new(cli: command)
    output = req(@exec, 'show_cmd_text_output', args)
    self.class.filter_cli(cli_output: output, context: context, value: value)
  end

  def req(stub, type, args)
    if cache_enable? && @cache_hash[type] && @cache_hash[type][args.cli]
      return @cache_hash[type][args.cli]
    end

    debug "Sending '#{type}' request:"
    if args.is_a?(ShowCmdArgs) || args.is_a?(CliConfigArgs)
      debug "  with cli: '#{args.cli}'"
    end
    output = Cisco::Client.silence_warnings do
      response = stub.send(type, args,
                           timeout:  @timeout,
                           username: @username,
                           password: <PASSWORD>)
{'fraction_non_alphanumeric': 0.11170773803816282, 'fraction_numerical': 0.004986096461789241, 'mean_word_length': 2.7491013659237957, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '121299', 'n_tokens_mistral': 3188, 'n_tokens_neox': 3085, 'n_words': 1019}