def post_json(session: requests.Session, url: str, json: Any) -> requests.models.Response: """ Post JSON to the Forest endpoint. """ logger.debug("Sending POST request to %s. Body: %s", url, json) res = session.post(url, json=json) if res.status_code >= 400: raise parse_error(res) return res
def get_json(session: requests.Session, url: str, params: Optional[Dict[Any, Any]] = None) -> Any: """ Get JSON from a Forest endpoint. """ logger.debug("Sending GET request to %s. Params: %s", url, params) res = session.get(url, params=params) if res.status_code >= 400: raise parse_error(res) return res.json()
def _parse_auth_token(path: str, required_keys: Iterable[str]) -> Optional[dict]: try: with open(abspath(expanduser(path)), "r") as f: token = json.load(f) invalid_values = [k for k in required_keys if not isinstance(token.get(k), str)] if len(invalid_values) == 0: return token logger.warning(f"Failed to parse auth token at {path}.") logger.warning(f"Invalid {invalid_values}.") except json.decoder.JSONDecodeError: logger.warning(f"Failed to parse auth token at {path}. Invalid JSON.") except FileNotFoundError: logger.debug("Auth token at %s not found.", path)
def __init__( self, client_public_key: bytes, client_secret_key: bytes, server_public_key: bytes, expires_at: Union[int, float, str], qpu_endpoint: str, qpu_compiler_endpoint: str, ): self.client_public_key = client_public_key self.client_secret_key = client_secret_key self.server_public_key = server_public_key self.expires_at = float(expires_at) if expires_at else None self.qpu_endpoint = qpu_endpoint self.qpu_compiler_endpoint = qpu_compiler_endpoint logger.debug("New engagement created: \n%s", self)
def _build_client(self) -> Client: endpoint: Optional[str] = None if self.endpoint: endpoint = self.endpoint elif self.session and self.session.config.qpu_url: endpoint = self.session.config.qpu_url if endpoint is None: raise UserMessageError( """It looks like you've tried to run a program against a QPU but do not currently have a reservation on one. To reserve time on Rigetti QPUs, use the command line interface, qcs, which comes pre-installed in your QMI. From within your QMI, type: qcs reserve --lattice <lattice-name> For more information, please see the docs at https://www.rigetti.com/qcs/docs/reservations or reach out to Rigetti support at [email protected].""") logger.debug("QPU Client connecting to %s", endpoint) return Client(endpoint, auth_config=self._get_client_auth_config())
def _engage(self) -> Optional["Engagement"]: """ The heart of the QPU authorization process, ``engage`` makes a request to the dispatch server for the information needed to communicate with the QPU. This is a standard GraphQL request, authenticated using the access token retrieved from Forest Server. The response includes the endpoints to the QPU and QPU Compiler Server, along with the set of keys necessary to connect to the QPU and the time at which that key set expires. """ query = """ mutation Engage($name: String!) { engage(input: { lattice: { name: $name }}) { success message engagement { type qpu { endpoint credentials { clientPublic clientSecret serverPublic } } compiler { endpoint } expiresAt } } } """ if not self.lattice_name: logger.debug( "ForestSession requires lattice_name in order to engage") return None logger.debug("Requesting engagement from %s", self.config.dispatch_url) variables = dict(name=self.lattice_name) query_response = self._request_graphql_retry(self.config.dispatch_url, query=query, variables=variables) if query_response.get("errors"): errors = query_response.get("errors", []) error_messages = map(lambda error: error["message"], errors) # type: ignore raise UserMessageError( f"Failed to engage: {','.join(error_messages)}") engagement_response = query_response.get("data", {}).get("engage", None) if engagement_response and engagement_response.get("success") is True: logger.debug("Engagement successful") engagement_data = engagement_response.get("engagement", {}) return Engagement( client_secret_key=engagement_data.get("qpu", {}).get( "credentials", {}).get("clientSecret", "").encode("utf-8"), client_public_key=engagement_data.get("qpu", {}).get( "credentials", {}).get("clientPublic", "").encode("utf-8"), server_public_key=engagement_data.get("qpu", {}).get( "credentials", {}).get("serverPublic", "").encode("utf-8"), expires_at=engagement_data.get("expiresAt", {}), qpu_endpoint=engagement_data.get("qpu", {}).get("endpoint"), qpu_compiler_endpoint=engagement_data.get("compiler", {}).get("endpoint"), ) else: raise UserMessageError( f"Unable to engage {self.lattice_name}: " f"{engagement_response.get('message', 'No message')}")