text: # -*- coding: utf-8 -*-
  
  # --------------------------------------------------------------------------
  # Copyright Commvault Systems, Inc.
  #
  # 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.
  # --------------------------------------------------------------------------
  
  """Main file for performing DR Orchestration specific operations.
  
  
  DROrchestrationOperations:  Class for representing all the DR orchestration operations from failover groups
                              or replication monitor
  
  
  DROrchestrationOperations:
      __init__(commcell_object)                       -- Initialise object of DROrchestrationOperations
  
      __repr__()                                      -- Return the DROrchestrationOperations
  
      testboot()                                      -- Call testboot operation
  
      planned_failover()                              -- Call Planned failvoer operation
  
      unplanned_failover()                            -- Call Unplanned Failover operation
  
      failback()                                      -- Call failback operation
  
      undo_failover()                                 -- Call UndoFailover operation
  
      revert_failover()                               -- Call RevertFailover operation
  
      point_in_time_failover()                        -- Call PointInTimeFailover operation
  
      reverse_replication()                           -- Call ReverseReplication operation
  
      validate_dr_orchestration_job(jobId)            -- Validate DR orchestration job Id
  
  
      ##### internal methods #####
      _construct_dr_orchestration_operation_json()    -- Construct dr orchestration operation json
  
      _construct_reverse_replication_json()           -- Construct reverse replication json
  
      _call_dr_orchestration_task
      (dr_orchestration_json)                         -- Call DR orchestration task
  
      _call_reverse_replication_task
      (dr_orchestration_json)                         -- Call reverse replication
  
      _get_dr_orchestration_job_stats
      (jobId, replicationId)                          -- Gets DR orchetration job phase types and states
  
  
      ##### properties #####
      _json_task()                                    -- Returns task json
  
      _json_dr_orchestration_subtasks()               -- Returns DR orchestration subtasks json
  
      _json_dr_orchestration()                        -- Returns DR orchestration json
  
      _dr_group_id()                                  -- Returns DR group Id
  
      dr_orchestration_options()                      -- DR orchestration options
  
      dr_orchestration_job_phase()                    -- DR orchestration job phase type
  
  
  """
  
  from __future__ import absolute_import
  from __future__ import unicode_literals
  
  from past.builtins import basestring
  from ..exception import SDKException
  
  
  class DROrchestrationOperations(object):
      """Class for invoking DROrchestration operations in the commcell."""
  
      def __init__(self, commcell_object):
          """Initialize object of the DROrchestrationOperations.
  
              Args:
                  commcell_object (object)  --  instance of the Commcell class
  
              Returns:
                  object - instance of the DROrchestrationOperations class
          """
          self._commcell_object = commcell_object
          self._services = commcell_object._services
  
          ####### init REST API URLS #########
          self._CREATE_TASK = self._commcell_object._services['CREATE_TASK']
          self._REVERSE_REPLICATION_TASK = self._commcell_object._services[
              'REVERSE_REPLICATION_TASK']
  
          #### init variables ######
          self._dr_orchestration_option = None
          self._dr_orchestration_job_phase = None
          self._dr_group_Id = 0
  
      def __repr__(self):
          """String representation of the instance of this class."""
          representation_string = '"DROrchestrationOperations: instance for commcell: "{1}"'
          return representation_string.format(
              self._commcell_object.commserv_name)
  
      @property
      def dr_orchestration_job_phase(self):
          """
          Args:
  
          Returns: DR orchestration job phase dict
  
          Raises:
          """
          if not self._dr_orchestration_job_phase:
              _dr_orchestration_job_phase = {
                  "0": "Script Execution",
                  "1": "Power On",
                  "2": "Power Off",
                  "3": "Reboot",
                  "4": "Guest Tools Status Check",
                  "5": "Create Network Switch",
                  "6": "Delete Network Switch",
                  "7": "Replication",
                  "8": "Backup",
                  "9": "Configure Network Switch",
                  "10": "Port Configuration",
                  "11": "IP Masquerading",
                  "12": "Static IP Mapping",
                  "13": "Intialization",
                  "14": "Waiting on IP Assignment",
                  "15": "Disable Sync",
                  "16": "Enable Sync",
                  "17": "Create Snapshot",
                  "18": "Delete Snapshot",
                  "19": "Revert Snapshot",
                  "20": "Disable Network Adapter",
                  "21": "Auxiliary Copy",
                  "22": "Post Operation",
                  "23": "Backup Copy",
                  "24": "Shutdown",
                  "25": "Storage Operation",
                  "26": "Finalize",
                  "27": "DR Approval"
  
              }
  
              self._dr_orchestration_job_phase = _dr_orchestration_job_phase
          return self._dr_orchestration_job_phase
  
      @property
      def dr_orchestration_options(self):
          """Getter dr orchestration options json"""
          return self._dr_orchestration_option
  
      @dr_orchestration_options.setter
      def dr_orchestration_options(self, value):
          """Setter dr orchestration options json"""
          self._dr_orchestration_option = value
  
      @property
      def dr_group_id(self):
          """Getter DR group Id"""
          return int(self.dr_orchestration_options.get("failoverGroupId", 0))
  
      @property
      def _json_task(self):
          """Getter for the task information in JSON"""
  
          _taks_option_json = {
              "ownerId": 1,
              "taskType": 1,
              "ownerName": "admin",
              "sequenceNumber": 0,
              "initiatedFrom": 2,
              "taskFlags": {
                  "disabled": False
              }
          }
  
          return _taks_option_json
  
      @property
      def _json_dr_orchestration_subtasks(self):
          """Getter for the subtask in DR orchestraion JSON . It is read only attribute"""
  
          _backup_subtask = {
              "subTaskType": 1,
              "operationType": 4046
          }
  
          return _backup_subtask
  
      @property
      def _json_dr_orchestration(self):
          """Getter for the DRorchestration task in failover group JSON . It is read only attribute"""
  
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          initiatedFrom = self.dr_orchestration_options.get(
              "initiatedfromMonitor", False)
  
          _dr_orchestration_json = {
              "operationType": int(self.dr_orchestration_options.get("DROrchestrationType")),
              "initiatedfromMonitor": initiatedFrom,
              "advancedOptions": {
                  "skipDisableNetworkAdapter": self.dr_orchestration_options.get("skipDisableNetworkAdapter", False)
              }
          }
  
          # if initiated from monitor set To True
          if initiatedFrom:
  
              _dr_orchestration_json.update({
                      "replicationInfo": {
                          "replicationId": self.dr_orchestration_options.get("replicationIds", [0])
                      }
              })
  
          else:
              _dr_orchestration_json.update({
                  "vApp": {
                      "vAppId": int(self.dr_orchestration_options.get("failoverGroupId")),
                      "vAppName": self.dr_orchestration_options.get("failoverGroupName")
                  }
              })
  
          return _dr_orchestration_json
  
      def testboot(self):
          """Performs testboot failover operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the Testboot job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "7"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def planned_failover(self):
          """Performs Planned failover operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the Planned Failover job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "1"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def unplanned_failover(self):
          """Performs UnPlanned failover operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the Unplanned Failover job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "3"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def failback(self):
          """Performs Failback operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the failback job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "2"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def undo_failover(self):
          """Performs Undo Failover operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the failback job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "6"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def reverse_replication(self):
          """Performs Reverse Replication operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the failback job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "9"
          dr_orchestration_json = self._construct_reverse_replication_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_reverse_replication_task(dr_orchestration_json)
  
      def revert_failover(self):
          """Performs Revert Failover operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the failback job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "4"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def point_in_time_failover(self):
          """Performs Point in time Failover operation.
  
              Args:
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the failback job triggered
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
          """
          if not isinstance(self.dr_orchestration_options, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          self.dr_orchestration_options["DROrchestrationType"] = "8"
          dr_orchestration_json = self._construct_dr_orchestration_operation_json()
  
          if not dr_orchestration_json:
              raise SDKException('DROrchestrationOperations', '101')
  
          return self._call_dr_orchestration_task(dr_orchestration_json)
  
      def validate_dr_orchestration_job(self, jobId):
          """ Validates DR orchestration job of jobId
              Args:
                  JobId: Job Id of the DR orchestration job
  
              Returns:
                  bool - boolean that represents whether the DR orchestration job finished successfully or not
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
                      If failover phase failed at any stage
          """
  
          if not isinstance(jobId, basestring):
              raise SDKException('DROrchestrationOperations', '101')
  
          _replicationIds = self.dr_orchestration_options.get(
              "replicationIds", [])
          if not _replicationIds:
              raise SDKException('DROrchestrationOperations', '101')
  
          # iterate over replication Ids
          for replicationId in iter(_replicationIds):
  
              dr_orchestration_job_stats_json = self._get_dr_orchestration_job_stats(
                  str(jobId), str(replicationId))
  
              if dr_orchestration_job_stats_json and isinstance(
                      dr_orchestration_job_stats_json, dict):
  
                  if "phase" in dr_orchestration_job_stats_json:
  
                      for phase in dr_orchestration_job_stats_json["phase"]:
  
                          phase_type = self.dr_orchestration_job_phase[str(
                              phase["phase"])]
                          phase_state = phase["status"]
  
                          if phase_state == 1:
                              o_str = 'Failed to complete phase: [' + str(
                                  phase_type) + '] status: [' + str(phase_state) + ']'
                              raise SDKException(
                                  'DROrchestrationOperations', '102', o_str)
  
                  else:
  
                      o_str = 'Failed to finish any phases in DR orchestration Job {0} \n'.format(
                          jobId)
                      raise SDKException(
                          'DROrchestrationOperations', '102', o_str)
  
          return True
  
  
  #################### private functions #####################
  
      def _get_dr_orchestration_operation_string(self, orchestration_type):
          """Getter for dr orchestration operation type"""
  
          _orchestration_string = ""
          if orchestration_type == 1:
              _orchestration_string = "Planned Failover"
  
          elif orchestration_type == 2:
              _orchestration_string = "Failback"
  
          elif orchestration_type == 3:
              _orchestration_string = "UnPlanned Failover"
  
          elif orchestration_type == 4:
              _orchestration_string = "Revert Failover"
  
          elif orchestration_type == 6:
              _orchestration_string = "Undo Failover"
  
          elif orchestration_type == 7:
              _orchestration_string = "TestBoot"
  
          elif orchestration_type == 8:
              _orchestration_string = "Point in Time Failover"
  
          elif orchestration_type == 9:
              _orchestration_string = "Reverse Replication"
  
          return _orchestration_string
  
      def _construct_dr_orchestration_operation_json(self):
          """
              Constructs DR orchestration operation json to invoke DR orchestration operation in the commcell
  
              Args:
  
              Returns: DR orchestration json dict
  
              Raises:
                  SDKException:
                      if response is empty
                      if response is not success
          """
          dr_orchestration_json = {
              "taskInfo": {
                  "task": self._json_task,
                  "subTasks": [
                      {
                          "subTaskOperation": 1,
                          "subTask": self._json_dr_orchestration_subtasks,
                          "options": {
                              "adminOpts": {
                                  "drOrchestrationOption": self._json_dr_orchestration
                              }
                          }
                      }
                  ]
              }
          }
  
          return dr_orchestration_json
  
      def _construct_reverse_replication_json(self):
          """
              Constructs reverse replication json to invoke reverse replication task in the commcell
  
              Args:
  
              Returns: Reverse replication task dict
  
              Raises:
                  SDKException:
                      if response is empty
                      if response is not success
          """
          dr_orchestration_json = {
  
              "drOrchestrationOption": self._json_dr_orchestration
  
          }
  
          return dr_orchestration_json
  
      def _call_dr_orchestration_task(self, dr_orchestration_json):
          """
              Invokes DR orchestration operation task
  
              Args: dr orchestration json
  
                      taskInfo':  {
                      'task':  {
                          'taskFlags':  {
                              'disabled':  0
                          },
                           'taskType':  1,
                           'ownerId':  1,
                           'initiatedFrom':  2,
                           'sequenceNumber':  0,
                           'ownerName':  'admin'
                      },
                       'subTasks':  {
                          'subTask':  {
                              'subTaskType':  1,
                               'operationType':  4046
                          },
                           'options':  {
                              'adminOpts':  {
                                  'drOrchestrationOption':  {
                                      'replicationInfo':  {
                                          'replicationId':  [
                                              {
                                                  'val':  3
                                              },
                                               {
                                                  'val':  4
                                              }
                                          ]
                                      },
                                       'vApp':  {
                                          'vAppId':  26,
                                           'vAppName':  'fg1-automation1x21'
                                      },
                                       'advancedOptions':  {
                                          'skipDisableNetworkAdapter':  0
                                      },
                                       'operationType':  7,
                                       'initiatedfromMonitor':  0
                                  }
                              }
                          },
                           'subTaskOperation':  1
                      }
                  }
              }
  
  
              Returns:
                  (JobId, TaskId) - JobId and taskId of the DR orchestration job triggered
  
              Raises:
                  SDKException:
                      if response is empty
                      if response is not success
          """
          if not isinstance(dr_orchestration_json, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          # passing the built json to start failover
          (flag, response) = self._commcell_object._cvpysdk_object.make_request(
              method='POST', url=self._CREATE_TASK, payload=dr_orchestration_json)
  
          if flag:
              if response.json():
                  if 'error' in response.json():
                      error_message = response.json()['error']['errorMessage']
                      o_str = 'Failed to start {0} job \nError: "{1}"'.format(
                          self._get_dr_orchestration_operation_string(self.dr_orchestration_options.get("DROrchestrationType")), error_message)
  
                      raise SDKException(
                          'DROrchestrationOperations', '102', o_str)
                  else:
                      # return object of corresponding Virtual Machine Policy
                      # here
                      task_id = response.json()['taskId']
                      job_id = response.json()['jobIds'][0]
                      return (job_id, task_id)
  
              else:
                  raise SDKException('Response', '102')
          else:
              response_string = self._commcell_object._update_response_(
                  response.text)
              raise SDKException('Response', '101', response_string)
  
      def _call_reverse_replication_task(self, dr_orchestration_json):
          """
              Create reverse replication task
  
              Args: DR orchestration json
  
                  drOrchestrationOption':  {
                      'replicationInfo':  {
                          'replicationId':  [
                              {
                                  'val':  3
                              },
                               {
                                  'val':  4
                              }
                          ]
                      },
  
                       'advancedOptions':  {
                          'skipDisableNetworkAdapter':  0
                      },
                       'operationType':  9,
                       'initiatedfromMonitor':  1
              }
  
  
              Returns:
                  (TaskId) - taskId of the created reverse replication schedule
  
              Raises:
                  SDKException:
                      if response is empty
                      if response is not success
          """
  
          if not isinstance(dr_orchestration_json, dict):
              raise SDKException('DROrchestrationOperations', '101')
  
          # passing the built json to start DR orchestration
          (flag, response) = self._commcell_object._cvpysdk_object.make_request(
              method='PUT', url=self._REVERSE_REPLICATION_TASK, payload=dr_orchestration_json)
  
          if flag:
              if response.json():
                  if 'error' in response.json():
                      error_message = response.json()['error']['errorMessage']
                      o_str = 'Failed to start {0} job \nError: "{1}"'.format(
                          self._get_dr_orchestration_operation_string(self.dr_orchestration_options.get("DROrchestrationType")), error_message)
  
                      raise SDKException(
                          'DROrchestrationOperations', '102', o_str)
                  else:
                      # return object of corresponding Virtual Machine Policy
                      # here
                      task_id = response.json()['taskId']
                      return (task_id)
  
              else:
                  raise SDKException('Response', '102')
          else:
              response_string = self._commcell_object._update_response_(
                  response.text)
              raise SDKException('Response', '101', response_string)
  
      def _get_dr_orchestration_job_stats(self, jobId, replicationId):
          """ Gets DR orchestration job stats json
              Args:
                  JobId: Job Id of the DR orchestration job
                  replicationId: replication Id of the DR orchestration
  
              Returns:
                  dict - DR orchestration job phases
                  {
                              "jobId": 4240,
                              "replicationId": 7,
                              "phase": [
                                  {
                                      "phase": 15,
                                      "status": 0,
                                      "startTime": {
                                          "_type_": 55,
                                          "time": 1516293332
                                      },
                                      "endTime": {
                                          "_type_": 55,
                                          "time": 1516293335
                                      },
                                      "entity": {
                                          "clientName": "failovervm1"
                                      }
                                  },
                                  {
                                      "phase": 17,
                                      "status": 0,
                                      "startTime": {
                                          "_type_": 55,
                                          "time": 1516293335
                                      },
                                      "endTime": {
                                          "_type_": 55,
                                          "time": 1516293340
                                      },
                                      "entity": {
                                          "clientName": "failovervm1"
                                      }
                                  },
                                  {
                                      "phase": 20,
                                      "status": 0,
                                      "startTime": {
                                          "_type_": 55,
                                          "time": 1516293340
                                      },
                                      "endTime": {
                                          "_type_": 55,
                                          "time": 1516293345
                                      },
                                      "entity": {
                                          "clientName": "failovervm1"
                                      }
                                  }
              }
  
              Raises:
                  SDKException:
                      if proper inputs are not provided
                      If DR orchestration phase failed at any stage
          """
  
          if not isinstance(jobId, basestring) and not isinstance(
                  replicationId, basestring):
              raise SDKException('DROrchestrationOperations', '101')
  
          _DR_JOB_STATS = self._commcell_object._services['DR_GROUP_JOB_STATS'] % (
              jobId, self.dr_group_id, replicationId)
  
          # passing the built json to get DR orchestration job phases
          (flag, response) = self._commcell_object._cvpysdk_object.make_request(
              method='GET', url=_DR_JOB_STATS)
  
          if flag:
              if response.json():
                  if 'error' in response.json():
                      error_message = response.json()['error']['errorMessage']
                      o_str = 'Failed to validate DR orchestration job {0} \nError: "{1}"'.format(jobId,
                                                                                                  error_message)
  
                      raise SDKException(
                          'DROrchestrationOperations', '102', o_str)
                  else:
  
                      if 'job' in response.json():
  
                          # return DR orchestration job phases
                          return (response.json()["job"][0])
  
                      else:
                          raise SDKException(
                              'DROrchestrationOperations', '102', 'Failed to start DR orchestration job')
  
              else:
                  raise SDKException('Response', '102')
          else:
              response_string = self._commcell_object._update_response_(
                  response.text)
              raise SDKException('Response', '101', response_string)
  