How to build CDK Assembly using Python aws_cdk.cx_api - python

I'm desperate so any help is appreciated.
I'm trying to modify my current CDK out using cloud assembly in Python.
I can't find any examples, nor proper documentation for python, only reference guide.
This is my code:
import os
import subprocess
import aws_cdk.cx_api as cxapi
import aws_cdk.cloud_assembly_schema as cxschema
class my_class():
def synth():
ASSEMBLY_PATH = 'igor_cdk'
result = subprocess.run(['cdk', 'synth', '-o', ASSEMBLY_PATH], stdout=subprocess.PIPE)
my_stuff = result.stdout.decode('utf-8')
new_stack_name = original_stack_name+TEMP_OUT
print(new_stack_name)
cloud_assembly = cxapi.CloudAssembly(ASSEMBLY_PATH);
orig_stack_assembly = cloud_assembly.get_stack_by_name(original_stack_name)
logical_Ids = orig_stack_assembly.find_metadata_by_type("aws:cdk:logicalId")
cab = cxapi.CloudAssemblyBuilder(ASSEMBLY_PATH)
cab.add_artifact(new_stack_name, type = cxschema.ArtifactType.ASSET_MANIFEST, properties = orig_stack_assembly.manifest)
Then, In my dummy test, I call this:
print(stack_info.synth("Test", "Targeta"))
And that's executed with pytest.
Just for comparison, I got it working in Typescript:
const cab: CloudAssemblyBuilder = new CloudAssemblyBuilder(ASSEMBLY_PATH);
cab.addArtifact(new_stack_name, stack.manifest);
cab.buildAssembly();
I expected similar/same behavior, but I just can't figure out how to do it in python, and since my whole code base is in python, I'd just love to have it all done in one place, rather than reworking the whole thing in TS.
Edit:
If I pass the stack.manifest, I'm getting the following error:
jsii.errors.JSIIError: Value did not match any type in union:
Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.AwsCloudFormationStackProperties', Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.AssetManifestProperties',
Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.TreeArtifactProperties',
Wire struct type '#aws-cdk/cloud-assembly-schema.ArtifactManifest' does not match expected '#aws-cdk/cloud-assembly-schema.NestedCloudAssemblyProperties'
And if I pass the whole stack assembly object, I run in even weirder problem:
jsii.errors.JavaScriptError:
RangeError: Maximum call stack size exceeded
at /private/var/folders/z6/c91mcs6j4g93t2856_p_51nr0000gn/T/jsii-kernel-35iS5M/node_modules/#aws-cdk/cx-api/lib/cloud-assembly.js:307:53

Related

TypeError calling .NET method using Pythonnet

I'm having a problem calling a method from a .NET dll linked to the eBUS SDK. The end goal of the code is to communicated to a GigE connected camera using python.
In C#, the method is:
public void SetStreamDestination( string aIPAddress, ushort aDataPort ) , and is part of a class called PvDeviceGEV.
In Python, I'm using pythonnet to import the dll. I'm then using this code:
from PvDotNet import PvDeviceGEV
from PvDotNet import PvStreamGEV
DeviceGEV = PvDeviceGEV()
Stream = PvStreamGEV()
LocalIP = Stream.LocalIPAddress
LocalPort = Stream.LocalPort
DeviceGEV.SetStreamDestination(LocalIP, LocalPort)
This results in an error:
TypeError: No method matches given arguments for SetStreamDestination: (<class 'str'>, <class 'int>)
Seeing as the types of IPAddress and aDataPort should be string and UInt16 respectively, I don't understand this error. I've been able to call other methods from this class. This is my first time trying to import functions from another language into Python. Any help understanding or correcting this error would be appreciated.
I solved this by changing
SetStreamDestination(LocalIP, LocalPort) to SetStreamDestination(LocalIP, UInt16(LocalPort))

Constructor error using mXparser with Pythonnet

I am trying to use mXparser from Python. It loads without problem, but as soon as try to call the expression function with a string (as in the help examples), I get an error, TypeError: no constructor matches given arguments.
import clr
dllpath = r'C:\...\GitHub\MathParser.org-mXparser\CURRENT\c-sharp\bin\Release\MathParser.org-mXparser.dll'
import org.mariuszgromada.math.mxparser as mx
expr_01 = mx.Expression('2 + 1')
Initially I took this to mean that I needed to specify the type of the string I was passing, but I don't think this is it. Any ideas? I compiled the mXparser dll with .NET Framework 4.5.2 (I did not choose the option to make it COM-visible).
you can run
mx.Expression.Overloads to see what argument type it needs. The type can be imported by from System import String, etc
Explicitly, construct the c# type
from System import String
str3 = String('2 + 1')
expr_01 = mx.Expression(str3)

How to read file capabilities using Python?

On Linux systems root privileges can be granted more selectively than adding the setuid bit using file capabilities. See capabilities(7) for details. These are attributes of files and can be read using the getcap program. How can these attributes be retrieved in Python?
Even though running the getcap program using e.g. subprocess for answering such a question is possible it is not desirable when retrieving very many capabilities.
It should be possible to devise a solution using ctypes. Are there alternatives to this approach or even libraries facilitating this task?
Python 3.3 comes with os.getxattr. If not, yeah... one way would be using ctypes, at least to get the raw stuff, or maybe use pyxattr
For pyxattr:
>>> import xattr
>>> xattr.listxattr("/bin/ping")
(u'security.capability',)
>>> xattr.getxattr("/bin/ping", "security.capability")
'\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
For Python 3.3's version, it's essentially the same, just importing os, instead of xattr. ctypes is a bit more involved, though.
Now, we're getting the raw result, meaning that those two are most useful only retrieving textual attributes. But... we can use the same approach of getcap, through libcap itself:
import ctypes
libcap = ctypes.cdll.LoadLibrary("libcap.so")
cap_t = libcap.cap_get_file('/bin/ping')
libcap.cap_to_text.restype = ctypes.c_char_p
libcap.cap_to_text(cap_t, None)
which gives me:
'= cap_net_raw+p'
probably more useful for you.
PS: note that cap_to_text returns a malloced string. It's your job to deallocate it using cap_free
Hint about the "binary gibberish":
>>> import struct
>>> caps = '\x00\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> struct.unpack("<IIIII", caps)
(33554432, 8192, 0, 0, 0)
In that 8192, the only active bit is the 13th. If you go to linux/capability.h, you'll see that CAP_NET_RAW is defined at 13.
Now, if you wan to write a module with all those constants, you can decode the info. But I'd say it's much more laborious than just using ctypes + libcap.
I tried the code from Ricardo Cárdenes's answer, but it did not work properly for me, because some details of the ctypes invocation incorrect. This issue caused a truncated path string to be passed to getxattr(...) inside of libcap, which thus returned the wrong capabilities list for the wrong item (the / directory, or other first path character, and not the actual path).
It is very important to remember and account for the difference between str and bytes in Python 3.X. This code works properly on Python 3.5/3.6:
#!/usr/bin/env python3
import ctypes
import os
import sys
# load shared library
libcap = ctypes.cdll.LoadLibrary('libcap.so')
class libcap_auto_c_char_p(ctypes.c_char_p):
def __del__(self):
libcap.cap_free(self)
# cap_t cap_get_file(const char *path_p)
libcap.cap_get_file.argtypes = [ctypes.c_char_p]
libcap.cap_get_file.restype = ctypes.c_void_p
# char* cap_to_text(cap_t caps, ssize_t *length_p)
libcap.cap_to_text.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
libcap.cap_to_text.restype = libcap_auto_c_char_p
def cap_get_file(path):
cap_t = libcap.cap_get_file(path.encode('utf-8'))
if cap_t is None:
return ''
else:
return libcap.cap_to_text(cap_t, None).value.decode('utf-8')
print(cap_get_file('/usr/bin/traceroute6.iputils'))
print(cap_get_file('/usr/bin/systemd-detect-virt'))
print(cap_get_file('/usr/bin/mtr'))
print(cap_get_file('/usr/bin/tar'))
print(cap_get_file('/usr/bin/bogus'))
The output will look like this (anything nonexistent, or with no capabilities set just returns '':
= cap_net_raw+ep
= cap_dac_override,cap_sys_ptrace+ep
= cap_net_raw+ep

How do I (using python) correctly create and pass a ctypes structure to a WER API function?

First off, I found the following two similar questions:
Passing Structure to Windows API in python ctypes
ctypes and passing a by reference to a function
The first does not have an accepted answer, and I do not think that I'm doing anything in separate processes. The second simply points out pointer() and byref(), both of which I have tried using to no avail.
Now, on to my question:
I am trying to call the function WERReportCreate with my own pReportInformation (which is a pointer to a struct whose first data value is its own size). This fails in various ways, depending on how I go about it, but I'm not sure how to do it correctly. It is complicated by the fact that one of the requirements is that the structure know it's own size, which I'm not sure how to programatically determine (though if that was the only issue, I think I would have guessed the right value by now). The relevant information from the WER API is shown below:
HRESULT WINAPI WerReportCreate(
__in PCWSTR pwzEventType,
__in WER_REPORT_TYPE repType,
__in_opt PWER_REPORT_INFORMATION pReportInformation,
__out HREPORT *phReportHandle
);
(full info at http://msdn.microsoft.com/en-us/library/windows/desktop/bb513625%28v=vs.85%29.aspx)
typedef struct _WER_REPORT_INFORMATION {
DWORD dwSize;
HANDLE hProcess;
WCHAR wzConsentKey[64];
WCHAR wzFriendlyEventName[128];
WCHAR wzApplicationName[128];
WCHAR wzApplicationPath[MAX_PATH];
WCHAR wzDescription[512];
HWND hwndParent;
} WER_REPORT_INFORMATION, *PWER_REPORT_INFORMATION;
(full info at http://msdn.microsoft.com/en-us/library/windows/desktop/bb513637%28v=vs.85%29.aspx)
This is the code that I have tried:
import ctypes
import ctypes.wintypes
class ReportInfo( ctypes.Structure):
_fields_ = [ ("dwSize", ctypes.wintypes.DWORD),
("hProcess", ctypes.wintypes.HANDLE),
("wzConsentKey", ctypes.wintypes.WCHAR * 64),
("wzFriendlyEventName", ctypes.wintypes.WCHAR * 128),
("wzApplicationName", ctypes.wintypes.WCHAR * 128),
("wzApplicationPath", ctypes.wintypes.WCHAR * ctypes.wintypes.MAX_PATH),
("wzDescription", ctypes.wintypes.WCHAR * 512),
("hwndParent", ctypes.wintypes.HWND) ]
def genReportInfo():
import os
size = 32 #Complete SWAG, have tried many values
process = os.getpid()
parentwindow = ctypes.windll.user32.GetParent(process)
werreportinfopointer = ctypes.POINTER(ReportInfo)
p_werinfo = werreportinfopointer()
p_werinfo = ReportInfo(size, process, "consentkey", "friendlyeventname", "appname", "apppath", "desc", parentwindow)
return p_werinfo
if __name__ == '__main__':
reporthandle = ctypes.wintypes.HANDLE()
res = ctypes.wintypes.HRESULT()
### First pass NULL in as optional parameter to get default behavior ###
p_werinfo = None
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, p_werinfo, ctypes.byref(reporthandle))
print "Return Code",res,"\nHandle",reporthandle #Return Code 0, reporthandle is correct (verified by submitting report in a different test)
p_werinfo = genReportInfo() # Create our own struct
### Try Again Using Our Own Struct (via 'byref') ###
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, ctypes.byref(p_werinfo), ctypes.byref(reporthandle))
print "Return Code",res,"\nHandle",reporthandle #Return Code Nonzero, reporthandle is None
### Try Again Using Our Own Struct (directly) ###
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, p_werinfo, ctypes.byref(reporthandle))
print "Return Code",res,"\nHandle",reporthandle #Exception Occurs, Execution halts
And this is the output I get:
Return Code 0
Handle c_void_p(26085328)
Return Code -2147024809
Handle c_void_p(None)
Traceback (most recent call last):
File "test.py", line 40, in <module>
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', s.byref(reporthandle))
WindowsError: exception: access violation writing 0x0000087C
The fact that it works when I pass in a null, but not when I actually pass my (reference to my?) structure suggests to me I have one of three problems: I am not creating the structure correctly (I'm not certain the wzConsentKey is correctly defined), or I am not correctly figuring out the struct's size (I'm actually using struct.calcsize with various options to get initial guesses, and adding and subtracting 1 randomly), or I am not correctly passing the (reference to the?) structure.
Here is where I've hit a deadend. Any help would be appreciated (as well as suggestions for how to improve the clarity, formatting, or quality of my question; this is my first post).
The general short answer to the posted question is: Be sure you are putting the correct information into the structure, other than that, the provided code is a good example of creating and passing a structure. Here's what solved my problem specifically:
There were two issues with the provided code: First, as Mark Tolonen pointed out, I was passing an incorrect size. Using ctypes.sizeof(ReportInfo) solved that problem. The second issue was that I was using a process ID where a process handle was required. Using OpenProcess to obtain a valid process handle in place of my "process" argument solved the second problem.
To anyone debugging similar issues in the future, printing the HRESULTS out as hex numbers rather than integers to make better sense of the return codes:
print "Return Code %08x" % (res & 0xffffffff)
This, in my case, produced the following results:
Return Code 80070057
for my original error, and
Return Code 80070006
for the second error. Using the information at http://msdn.microsoft.com/en-us/library/bb446131.aspx , I saw the first half was metadata, the second half was my actual error code.
After converting the Error Code part of the Hex number back to decimal, I used http://msdn.microsoft.com/en-us/library/bb202810.aspx to determine that
Error Code 87 (57 in hex) meant "Parameter Incorrect" (size was wrong)
and
Error Code 6 (6 in hex) meant "The Handle is Invalid" (I was passing in a process ID).
You can use ctypes.sizeof(ReportInfo) to obtains the size in bytes of the structure.
Simply create the ReportInfo instance with genReportInfo. You don't need a pointer at this point:
def genReportInfo():
import os
size = ctypes.sizeof(ReportInfo)
process = os.getpid()
parentwindow = ctypes.windll.user32.GetParent(process)
return ReportInfo(size, process, "consentkey", "friendlyeventname", "appname", "apppath", "desc", parentwindow)
Call WerReportCreate like this. byref passes the pointer to the ReportInfo instance.
werinfo = genReportInfo()
res = ctypes.windll.wer.WerReportCreate(u'pwzEventType', 2, ctypes.byref(werinfo), ctypes.byref(reporthandle))
I think that will work for you. I don't have wer.dll so I can't test it.

Python c_types .dll functions (pari library)

Alright, so a couple days ago I decided to try and write a primitive wrapper for the PARI library. Ever since then I've been playing with ctypes library in loading the dll and accessing the functions contained using code similar to the following:
from ctypes import *
libcyg=CDLL("<path/cygwin1.dll") #It needs cygwin to be loaded. Not sure why.
pari=CDLL("<path>/libpari-gmp-2.4.dll")
print pari.fibo #fibonacci function
#prints something like "<_FuncPtr object at 0x00BA5828>"
So the functions are there and they can potentially be accessed, but I always receive an access violation no matter what I try. For example:
pari.fibo(5) #access violation
pari.fibo(c_int(5)) #access violation
pari.fibo.argtypes = [c_long] #setting arguments manually
pari.fibo.restype = long #set the return type
pari.fibo(byref(c_int(5))) #access violation reading 0x04 consistently
and any variation on that, including setting argtypes to receive pointers.
The Pari .dll is written in C and the fibonacci function's syntax within the library is GEN fibo(long x).
Could it be the return type that's causing these errors, as it is not a standard int or long but a GEN type, which is unique to the PARI library? Any help would be appreciated. If anyone is able to successfully load the library and use ANY function from within python, please tell; I've been at this for hours now.
EDIT: Seems as though I was simply forgetting to initialize the library. After a quick pari.pari_init(4000000,500000) it stopped erroring. Now my problem lies in the in the fact that it returns a GEN object; which is fine, but whenever I try to reference the address to which it points, it's always 33554435, which I presume is still an address. I'm trying further commands and I'll update if I succeed in getting the correct value of something.
You have two problems here, one give fibo the correct return type and two convert the GEN return type to the value you are looking for.
Poking around the source code a bit, you'll find that GEN is defined as a pointer to a long. Also, at looks like the library provides some converting/printing GENs. I focused in on GENtostr since it would probably be safer for all the pari functions.
import cytpes
pari = ctypes.CDLL("./libpari.so.2.3.5") #I did this under linux
pari.fibo.restype = ctypes.POINTER(ctypes.c_long)
pari.GENtostr.restype = ctypes.POINTER(ctypes.c_char)
pari.pari_init(4000000,500000)
x = pari.fibo(100)
y = pari.GENtostr(x)
ctypes.string_at(y)
Results in:
'354224848179261915075'

Categories

Resources