AWS sagemaker endpoint received client (400) error - amazon-web-services

I've deployed a tensorflow multi-label classification model using a sagemaker endpoint as follows:
predictor = sagemaker_model.deploy(initial_instance_count=1, instance_type="ml.m5.2xlarge", endpoint_name='testing-2')
It gets deployed and works fine when I invoke it from the Sagemaker Jupyter instance:
sample = ['this movie was extremely good']
output=predictor.predict(sample)
output:
{'predictions': [[0.00370046496,
4.32942124e-06,
0.00080883503,
9.25126587e-05,
0.00023958087,
0.000130862]]}
However, I am unable to send a request to the deployed endpoint from other notebooks or sagemaker studio. I'm unsure of the request format.
I've tried several variations in the input format and still failed. The error message is as below:
sagemaker error
Request:
{
"body": {
"text": "Testing model's prediction on this text"
},
"contentType": "application/json",
"endpointName": "testing-2",
"customURL": "",
"customHeaders": [
{
"Key": "sm_endpoint_name",
"Value": "testing-2"
}
]
}
Error:
Error invoking endpoint: Received client error (400) from primary with message "{ "error": "Failed to process element:
0 key: text of 'instances' list. Error: INVALID_ARGUMENT: JSON object: does not have named input: text" }".
See https://us-west-2.console.aws.amazon.com/cloudwatch/home?region=us-west-2#logEventViewer:group=/aws/sagemaker/Endpoints/testing-2
in account 793433463428 for more information.
Is there any way to find out exactly how the model expects the request format to be?
Earlier I had the same model on my local system and the way I tested it was using this curl request:
curl -s -H 'Content-Type: application/json' -d '{"text": "what ugly posts"}' http://localhost:7070/sentiment
And it worked fine without any issues.
I've tried different formats and replaced the "text" key inside body with other words like "input", "body", nothing etc.

Based on your description above, I assume you are deploying the TensorFlow model using the SageMaker TensorFlow container.
If you want to view what your model expects as input you can use the saved_model CLI:
1
├── keras_metadata.pb
├── saved_model.pb
└── variables
├── variables.data-00000-of-00001
└── variables.index
!saved_model_cli show --all --dir {"1"}
After you have confirmed the input name above you can invoke the endpoint as follows:
import json
import boto3
client = boto3.client('runtime.sagemaker')
data = {"instances": ['this movie was extremely good']}
response = client.invoke_endpoint(EndpointName=<EndpointName>,
Body=json.dumps(data))
response_body = response['Body']
print(response_body.read())
The same payload can then also be used in Studio when invoking the endpoint.

Related

python, google cloud platform: unable to overwite a file from google bucket: CRC32 does not match

I am using python3 client to connect to google buckets and trying to the following
download 'my_rules_file.yaml'
modify the yaml file
overwrite the file
Here is the code that i used
from google.cloud import storage
import yaml
client = storage.Client()
bucket = client.get_bucket('bucket_name')
blob = bucket.blob('my_rules_file.yaml')
yaml_file = blob.download_as_string()
doc = yaml.load(yaml_file, Loader=yaml.FullLoader)
doc['email'].clear()
doc['email'].extend(["test#gmail.com"])
yaml_file = yaml.dump(doc)
blob.upload_from_string(yaml_file, content_type="application/octet-stream")
This is the error I get from the last line for upload
BadRequest: 400 POST https://storage.googleapis.com/upload/storage/v1/b/fc-sandbox-datastore/o?uploadType=multipart: {
"error": {
"code": 400,
"message": "Provided CRC32C \"YXQoSg==\" doesn't match calculated CRC32C \"EyDHsA==\".",
"errors": [
{
"message": "Provided CRC32C \"YXQoSg==\" doesn't match calculated CRC32C \"EyDHsA==\".",
"domain": "global",
"reason": "invalid"
},
{
"message": "Provided MD5 hash \"G/rQwQii9moEvc3ZDqW2qQ==\" doesn't match calculated MD5 hash \"GqyZzuvv6yE57q1bLg8HAg==\".",
"domain": "global",
"reason": "invalid"
}
]
}
}
: ('Request failed with status code', 400, 'Expected one of', <HTTPStatus.OK: 200>)
why is this happening. This seems to happen only for ".yaml files".
The reason for your error is because you are trying to use the same blob object for both downloading and uploading this will not work you need two separate instances... You can find some good examples here Python google.cloud.storage.Blob() Examples
You should use a seperate blob instance to handle the upload you are trying with only one...
.....
blob = bucket.blob('my_rules_file.yaml')
yaml_file = blob.download_as_string()
.....
the second instance is needed here
....
blob.upload_from_string(yaml_file, content_type="application/octet-stream")
...

Pyspark - read data from elasticsearch cluster on EMR

I am trying to read data from elasticsearch from pyspark. I was using the elasticsearch-hadoop api in Spark. The es cluster sits on aws emr, which requires credential to sign in. My script is as below:
from pyspark import SparkContext, SparkConf sc.stop()
conf = SparkConf().setAppName("ESTest") sc = SparkContext(conf=conf)
es_read_conf = { "es.host" : "vhost", "es.nodes" : "node", "es.port" : "443",
"es.query": '{ "query": { "match_all": {} } }',
"es.input.json": "true", "es.net.https.auth.user": "aws_access_key",
"es.net.https.auth.pass": "aws_secret_key", "es.net.ssl": "true",
"es.resource" : "index/type", "es.nodes.wan.only": "true"
}
es_rdd = sc.newAPIHadoopRDD( inputFormatClass="org.elasticsearch.hadoop.mr.EsInputFormat",
keyClass="org.apache.hadoop.io.NullWritable",
valueClass="org.elasticsearch.hadoop.mr.LinkedMapWritable", conf=es_read_conf)
Pyspark keeps throwing error:
py4j.protocol.Py4JJavaError: An error occurred while calling
z:org.apache.spark.api.python.PythonRDD.newAPIHadoopRDD.
: org.elasticsearch.hadoop.rest.EsHadoopInvalidRequest: [HEAD] on
[index] failed; servernode:443] returned [403|Forbidden:]
I checked everything which all made sense except for the user and pass entries, would aws access key and secret key work here? We don't want to use the console user and password here for security purpose. Is there a different way to do the same thing?

How to run a Google Cloud Build trigger via cli / rest api / cloud functions?

Is there such an option? My use case would be running a trigger for a production build (deploys to production). Ideally, that trigger doesn't need to listen to any change since it is invoked manually via chatbot.
I saw this video CI/CD for Hybrid and Multi-Cloud Customers (Cloud Next '18) announcing there's an API trigger support, I'm not sure if that's what I need.
I did same thing few days ago.
You can submit your builds using gcloud and rest api
gcloud:
gcloud builds submit --no-source --config=cloudbuild.yaml --async --format=json
Rest API:
Send you cloudbuild.yaml as JSON with Auth Token to this url https://cloudbuild.googleapis.com/v1/projects/standf-188123/builds?alt=json
example cloudbuild.yaml:
steps:
- name: 'gcr.io/cloud-builders/docker'
id: Docker Version
args: ["version"]
- name: 'alpine'
id: Hello Cloud Build
args: ["echo", "Hello Cloud Build"]
example rest_json_body:
{"steps": [{"args": ["version"], "id": "Docker Version", "name": "gcr.io/cloud-builders/docker"}, {"args": ["echo", "Hello Cloud Build"], "id": "Hello Cloud Build", "name": "alpine"}]}
This now seems to be possible via API:
https://cloud.google.com/cloud-build/docs/api/reference/rest/v1/projects.triggers/run
request.json:
{
"projectId": "*****",
"commitSha": "************"
}
curl request (with using a gcloud command):
PROJECT_ID="********" TRIGGER_ID="*******************"; curl -X POST -T request.json -H "Authorization: Bearer $(gcloud config config-helper \
--format='value(credential.access_token)')" \
https://cloudbuild.googleapis.com/v1/projects/"$PROJECT_ID"/triggers/"$TRIGGER_ID":run
You can use google client api to create build jobs with python:
import operator
from functools import reduce
from typing import Dict, List, Union
from google.oauth2 import service_account
from googleapiclient import discovery
class GcloudService():
def __init__(self, service_token_path, project_id: Union[str, None]):
self.project_id = project_id
self.service_token_path = service_token_path
self.credentials = service_account.Credentials.from_service_account_file(self.service_token_path)
class CloudBuildApiService(GcloudService):
def __init__(self, *args, **kwargs):
super(CloudBuildApiService, self).__init__(*args, **kwargs)
scoped_credentials = self.credentials.with_scopes(['https://www.googleapis.com/auth/cloud-platform'])
self.service = discovery.build('cloudbuild', 'v1', credentials=scoped_credentials, cache_discovery=False)
def get(self, build_id: str) -> Dict:
return self.service.projects().builds().get(projectId=self.project_id, id=build_id).execute()
def create(self, image_name: str, gcs_name: str, gcs_path: str, env: Dict = None):
args: List[str] = self._get_env(env) if env else []
opt_params: List[str] = [
'-t', f'gcr.io/{self.project_id}/{image_name}',
'-f', f'./{image_name}/Dockerfile',
f'./{image_name}'
]
build_cmd: List[str] = ['build'] + args + opt_params
body = {
"projectId": self.project_id,
"source": {
'storageSource': {
'bucket': gcs_name,
'object': gcs_path,
}
},
"steps": [
{
"name": "gcr.io/cloud-builders/docker",
"args": build_cmd,
},
],
"images": [
[
f'gcr.io/{self.project_id}/{image_name}'
]
],
}
return self.service.projects().builds().create(projectId=self.project_id, body=body).execute()
def _get_env(self, env: Dict) -> List[str]:
env: List[str] = [['--build-arg', f'{key}={value}'] for key, value in env.items()]
# Flatten array
return reduce(operator.iconcat, env, [])
Here is the documentation so that you can implement more functionality: https://cloud.google.com/cloud-build/docs/api
Hope this helps.
If you just want to create a function that you can invoke directly, you have two choices:
An HTTP trigger with a standard API endpoint
A pubsub trigger that you invoke by sending a message to a pubsub topic
The first is the more common approach, as you are effectively creating a web API that any client can call with an HTTP library of their choice.
You should be able to manually trigger a build using curl and a json payload.
For details see: https://cloud.google.com/cloud-build/docs/running-builds/start-build-manually#running_builds.
Given that, you could write a Python Cloud function to replicate the curl call via the requests module.
I was in search of the same thing (Fall 2022) and while I haven't tested yet I wanted to answer before I forget. It appears to be available now in gcloud beta builds triggers run TRIGGER
you can trigger a function via
gcloud functions call NAME --data 'THING'
inside your function you can do pretty much anything possibile within Googles Public API's
if you just want to directly trigger Google Cloud Builder from git then its probably advisable to use Release version tags - so your chatbot might add a release tag to your release branch in git at which point cloud-builder will start the build.
more info here https://cloud.google.com/cloud-build/docs/running-builds/automate-builds

Decrypting SAML2 response using pysaml2 Python module

I am integrating my app with okta to have single sign on. Okta will be passing some user information in SAML response which I need to use in my application.
Hence, we decided to encrypt the saml response(xml) at IDP using my server(apache) public key.
Now I am trying to decrypt the saml2 response so that I can get the attributes.
My applications uses
Python 3.5
Django 1.11
pysaml2 python module
I am using below to validate/parse the saml2 response coming from okta
https://github.com/fangli/django-saml2-auth
If the saml response is not encrypted, I am able to process the response and able to get the user identity and user attributes from it.
However once it is encrypted at okta end with my server public key, I am not able to decrypt with my private key.
The saml setting I have at my application is below :
saml_settings = { 'metadata': {
"local": [ metadat_xml
],
},
'service': {
'sp': {
'endpoints': {
'assertion_consumer_service': [
(acs_url, BINDING_HTTP_REDIRECT),
(acs_url, BINDING_HTTP_POST),
(https_acs_url, BINDING_HTTP_REDIRECT),
(https_acs_url, BINDING_HTTP_POST)
],
},
'allow_unsolicited': True,
'authn_requests_signed': False,
'logout_requests_signed': True,
'want_assertions_signed': True,
'want_response_signed': False,
},
},
'key_file': "mykey.key", # private part
'cert_file': "mykey.crt", # public part
'xmlsec_binary': '/usr/bin/xmlsec1',
'encryption_keypairs': [{
'key_file': 'mykey.key',
'cert_file': 'mykey.crt',
}]
}
if 'ENTITY_ID' in settings.SAML2_AUTH:
saml_settings['entityid'] = settings.SAML2_AUTH['ENTITY_ID']
#print('entity id ' , settings.SAML2_AUTH['ENTITY_ID'])
if 'NAME_ID_FORMAT' in settings.SAML2_AUTH:
saml_settings['service']['sp']['name_id_format'] = settings.SAML2_AUTH['NAME_ID_FORMAT']
# NOTE-'NAME_ID_FORMAT is set to None above
spConfig = Saml2Config()
spConfig.load(saml_settings)
spConfig.allow_unknown_attributes = True
saml_client = Saml2Client(config=spConfig)
return saml_client
Then I have
saml_client = _get_saml_client(get_current_domain(r))
resp = r.POST.get('SAMLResponse', None)
authn_response = saml_client.parse_authn_request_response(resp, entity.BINDING_HTTP_POST )
This auth_response object is not returning me anything when the message is encrypted.
In logs I see below error
GbHvkJJM0WIsPYFGtiQ/0n+ux0tV/z/OKpT1AqEE74iRVHEHD7omP41iY/c4=
</ns3:CipherValue></ns3:CipherData><ns3:ReferenceList><ns3:DataReference
URI="#_648cdbd139564492f0bdfe4fbbda92f6" /></ns3:ReferenceList>
</ns3:EncryptedKey></ns1:EncryptedAssertion></ns0:Response>
2018-04-30 18:21:09,232 [DEBUG] sigver saml2.sigver decrypt(): Decrypt input
len: 15187
2018-04-30 18:21:09,233 [DEBUG] sigver saml2.sigver _run_xmlsec(): xmlsec
command: /usr/bin/xmlsec1 --decrypt --privkey-pem
/private.pem --id-attr:ID EncryptedKey --output /tmp/tmp7rt7g95u.xml
/tmp/tmpkhxwo8s4
2018-04-30 18:21:09,247 [DEBUG] sigver saml2.sigver _run_xmlsec(): xmlsec
p_out:
2018-04-30 18:21:09,247 [DEBUG] sigver saml2.sigver _run_xmlsec(): xmlsec
p_erryy:
func=xmlSecXPathDataExecute:file=xpath.c:line=273:obj=unknown:
subj=xmlXPtrEval:error=5:libxml2 library function
failed:expr=xpointer(id('_841612fffac65343e73f8913eeecfb30'))
func=xmlSecXPathDataListExecute:file=xpath.c:line=373:obj=unknown:
subj=xmlSecXPathDataExecute:error=1:xmlsec library function failed:
func=xmlSecTransformXPathExecute:file=xpath.c:line=483:
obj=xpointer:subj=xmlSecXPathDataExecute:error=1:xmlsec library function
failed:
func=xmlSecTransformDefaultPushXml:file=transforms.c:
line=2411:obj=xpointer:subj=xmlSecTransformExecute:error=1:xmlsec library
function failed:
func=xmlSecTransformCtxExecute:file=transforms.c:line=1302:
obj=unknown:subj=xmlSecTransformCtxXmlExecute:error=1:xmlsec library
function failed:
func=xmlSecKeyDataRetrievalMethodXmlRead:file=keyinfo.c:line=1178:
obj=retrieval-method:subj=xmlSecTransformCtxExecute:error=1:xmlsec library
function failed:
func=xmlSecKeyInfoNodeRead:file=keyinfo.c:line=114:obj=retrieval-method:
subj=xmlSecKeyDataXmlRead:error=1:xmlsec library function
failed:node=RetrievalMethod
func=xmlSecKeysMngrGetKey:file=keys.c:line=1349:obj=unknown:
subj=xmlSecKeyInfoNodeRead:error=1:xmlsec library function
failed:node=KeyInfo
func=xmlSecEncCtxEncDataNodeRead:file=xmlenc.c:line=957:
obj=unknown:subj=unknown:error=45:key is not found:
func=xmlSecEncCtxDecryptToBuffer:file=xmlenc.c:line=715:
obj=unknown:subj=xmlSecEncCtxEncDataNodeRead:error=1:xmlsec library function
failed:
func=xmlSecEncCtxDecrypt:file=xmlenc.c:line=623:
obj=unknown:subj=xmlSecEncCtxDecryptToBuffer:error=1:xmlsec library function
failed:
Error: failed to decrypt file
Error: failed to decrypt file "/tmp/tmpkhxwo8s4"
I am not sure why xmlsec1 command is failing and what I am missing here.
I have tried decrypting with my private key(self signed private key) here
https://www.samltool.com/decrypt.php
and it works
Could you please help me here and let me know what I am not doing correctly?
You need to add
saml_settings['id_attr_name'] = 'Id'
The default id attr is ID, but Okta uses Id. See xmlsec FAQ for more details.

Submit an App by Url to Firefox Marketplace

I can install it with URL, but i can't upload to firefox marketplace.
but i have 2 errors:
JSON Parse Error
Error: The webapp extension could not be parsed due to a syntax error in the JSON.
No JSON object could be decoded: line 1 column 0 (char 0)
well the json is this:
{
"name": "Snake",
"description": "Snake in html and js",
"launch_path": "/index.html",
"developer": {
"name": "ZiTAL",
"url": "https://github.com/ZiTAL/snakejs"
},
"icons": {
"128": "/img/snake-128.png"
},
"installs_allowed_from": ["*"]
}
Second error:
Manifests must be served with the HTTP header "Content-Type: application/x-web-app-manifest+json". See https://developer.mozilla.org/docs/Web/Apps/Manifest#Serving_manifests for more information.
well if i downloaded with wget:
wget http://myurl/manifest.webapp
the header is OK
HTTP eskaera bidalia, erantzunaren zain... 200 OK
Luzera: 267 [application/x-web-app-manifest+json]
Saving to: ‘manifest.webapp’
To validate the app, you need to put the manifest.webapp url, not the app url:
http://myurl/manifest.webapp
Second error:
You could try wget --save-headers and look in the output file, if the Content-Type header is really correct...