I wrote code that uses jclouds' HP cloud compute service, and everything worked well.
Yesterday I opened a new account on HP, and the code failed. Getting an error about version - so I assume HP upgraded their openstack version, however I can't find documentation anywhere to what should be changed in jclodus.
This is my code
public static ComputeServiceContext createJcloudsContext(String project, String key, String secretKey ) {
ServerConfig serverConfig = ApplicationContext.get().conf().server;
ComputeServiceContext context;
Properties overrides = new Properties();
overrides.put("jclouds.keystone.credential-type", "apiAccessKeyCredentials");
context = ContextBuilder.newBuilder( serverConfig.cloudProvider.label )
.credentials( project + ":" + key, secretKey )
.overrides(overrides)
.buildView(ComputeServiceContext.class);
return context;
}
And this is the error
java.util.NoSuchElementException: no endpoints for apiType compute are of version 1.1, or version agnostic: [Service{type=compute, name=Compute, endpoints=[Endpoint{versionId=2, region=region-a.geo-1, publicURL=https://region-a.geo-1.compute.hpcloudsvc.com/v2/10050594585198, internalURL=null, adminURL=null, versionInfo=https://region-a.geo-1.compute.hpcloudsvc.com/v2/, versionList=https://region-a.geo-1.compute.hpcloudsvc.com, tenantId=10050594585198}, Endpoint{versionId=2, region=region-b.geo-1, publicURL=https://region-b.geo-1.compute.hpcloudsvc.com/v2/10050594585198, internalURL=null, adminURL=null, versionInfo=https://region-b.geo-1.compute.hpcloudsvc.com/v2/, versionList=https://region-b.geo-1.compute.hpcloudsvc.com, tenantId=10050594585198}]}]
EDIT:
Barak's answer was good for the code snippet I posted - minimal code snippet for reproduction.
It seems that afterwards I get the same error for another line. below is the full code snippet.
Here is my code
final String provider = "hpcloud-compute";
final String user = USER_VALUE;
final String key = KEY_VALUE;
Properties overrides = new Properties();
overrides.setProperty("jclouds.keystone.credential-type", "apiAccessKeyCredentials");
overrides.setProperty(Constants.PROPERTY_ENDPOINT, "https://region-b.geo-1.identity.hpcloudsvc.com:35357/v2.0/");
overrides.setProperty("jclouds.api-version", "2");
ComputeServiceContext context = ContextBuilder
.newBuilder(provider)
.credentials(user, key)
.overrides(overrides)
.buildView(ComputeServiceContext.class);
Set<? extends ComputeMetadata> computeMetadatas = context.getComputeService().listNodes();
((RestContext<NovaApi, NovaAsyncApi>)context.unwrap()).getApi().getKeyPairExtensionForZone(zone);
((RestContext<NovaApi, NovaAsyncApi>)context.unwrap()).getApi().getSecurityGroupExtensionForZone(zone);
EDIT:
Turns out, the new HP cloud does not have availability zone "az1","az2"...
Instead, I need to pass "region-b.geo-1" and it works!
Add the following override:
overrides.put("jclouds.api-version":"2")
You may want to have a look at this forum post for more details: https://cloudifysource.zendesk.com/entries/30497773-Can-we-use-cloudify-with-HP-Cloud-environment-13-5-
Related
My code was perfectly fine in .net core 2.0 . I have ported by code to .net core 3.1 . Now I am getting the following error - "Cannot access a disposed object. Object name: 'RSA'."" . I googled and found an interesting [link][1] which was help full . In this article there was particular mention of commenting out using "using RSA". What is the implication of this ?
I found another good [link][2] which I used to build my code. The only issue with the sample is that it loads the public key each time token validation happens . I want to load my public key for validation upfront and not when the token is validated.
Below is my pseudo code
public CustomAuthorize(IConfiguration configuration)
{
_publicKey = config[publickey];
_issuer = config[issuer];
_publicKeySignature = convertpemtoSecurityKey(config[pem]) // type SecurityKey
_tokenParams = TokenValidationParameters();
}
public Microsoft.IdentityModel.Tokens.TokenValidationParameters TokenValidationParameters()
{
return new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,
Issuer = _issuer,
IssuerSigningKey = _publicKeySignature
}
}
public SecurityKey convertpemtoSecurityKey(String publicKey)
{
using RSA rsa = RSA.Create(); // if I remove 'using statement it works but not sure of the implications
rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKey), out _);
return new RsaSecurityKey(rsa);
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var tokenHandler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
try
{
tokenHandler.ValidateToken(TokenParams, __tokenParams , out validatedToken);
return;
}
}
Is it ok remove the "using" while using RSA.Create()? Is there any other workaround ?
[1]: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1433
[2]: https://vmsdurano.com/-net-core-3-1-signing-jwt-with-rsa/
I am using a software framework which on its part uses log4j-2.7 (I can't update the jars of the framework).
I have written a third party library which provides a RewritePolicy to re-format the log messages. The library uses log4j-2.7 as well.
Within the framework I do some loggings with MapMessage. However, the rewrite policy receives them as SimpleMessage or some other types of Message, but not as MapMessage.
Here is code examples from framwork:
var mapMessage = new MapMessage()
mapMessage.put("first", "first")
mapMessage.put("second", "second")
logger.info(mapMessage)
And here the rewrite method of the RewritePolicy:
#Override
public LogEvent rewrite(LogEvent source) {
final Message modifiedMessage;
Message origMessage = source.getMessage();
if (origMessage instanceof MapMessage) {
Map<String, Object> map = new HashMap<String, Object>(((MapMessage) origMessage).getData());
modifiedMessage = new SimpleMessage(createStringMessage((HashMap<String, Object>) map));
} else {
modifiedMessage = origMessage;
}
LogEvent modifiedLogEvent = new Log4jLogEvent.Builder(source).setMessage(modifiedMessage).build();
return modifiedLogEvent;
}
My problem was due to the fact that the sofware platform mentioned in my post did migrate from log4j 1 to 2, and as explained here https://logging.apache.org/log4j/2.x/manual/migration.html, I had to change the package from org.apache.log4j to org.apache.logging.log4j.
IoT modules can be created from the environment using :
ModuleClient.CreateFromEnvironmentAsync(settings)
However, there does not seem to be an equivalent method for devices. For now, I am setting the device connection string in the program to test it out, but is there a better way to read teh connection string from iotedge/config.yaml for all the edge devices deployed out there?
Methods to do so for .NET and python would be appreciated.
You can use a yaml parse library to deserialize the document, such as YamlDotNet. In fact, you can refer to YamlDocument in iot edge. But in the class, it does not provide a method to get the key value. Please refer to following code.
public class YamlDocument
{
readonly Dictionary<object, object> root;
public YamlDocument(string input)
{
var reader = new StringReader(input);
var deserializer = new Deserializer();
this.root = (Dictionary<object, object>)deserializer.Deserialize(reader);
}
public object GetKeyValue(string key)
{
if(this.root.ContainsKey(key))
{
return this.root[key];
}
foreach(var item in this.root)
{
var subItem = item.Value as Dictionary<object, object>;
if(subItem != null && subItem.ContainsKey(key))
{
return subItem[key];
}
}
return null;
}
}
And then you can get the device connection string from the config.yaml. If you use python, you can import yaml library to analysis the file.
StreamReader sr = new StreamReader(#"C:\ProgramData\iotedge\config.yaml");
var yamlString = sr.ReadToEnd();
var yamlDoc = new YamlDocument(yamlString);
var connectionString = yamlDoc.GetKeyValue("device_connection_string");
Console.WriteLine("{0}", connectionString);
To get the config file from the host, add the following to the docker deployment file. Note that the source file is config1.yaml which is the same as config.yaml except that it has read permissions for everyone not just root.
"createOptions": "{\"HostConfig\":{\"Binds\":[\"/etc/iotedge/config1.yaml:/app/copiedConfig.yaml\"]}}"
With the above line in place, the copiedConfig.yaml file can be used in the container, along with #Michael Xu's parsing code to derive teh connection string.
Long term, one may want to use the device provisioning service anyway but hope this helps for folks using device conenction strings for whatever reason..
Basically i am using a LetsEncrypt service to get a certificate byte[] back that i can turn into a X509Certificate2 but then it is missing the private key to then use it on a SSLStream. I have the private key as a RSAParameters but can also convert it to a byte[] but i can't seem to find a way to get the 2 together in the same X509Certificate2 so i can use it for AuthenticateAsServer on a SSLStream. The methods you would use for dotnet 4 don't seems to apply for dnx50 as far as i can tell. I working example would be perfect and i want to keep the solution in dnx50 as i want to deploy this to linux and windows boxes.
Basically trying to do something similar to Convert Certificate and Private Key to .PFX programatically in C# but to just create the X509 with private key though saving would be my next task.
From what i can tell so far i think that dnx50 does not allow you to create a cetificate object and to then add a private key to it like dotnet 4 did. Instead i think i need to pass in a a file or byte[] that contains both for this to work but i don't know how to merge my 2 byte arrays together or to format them.
Finally worked out a solution for this. Not ideal but it works. Basically it uses bouncyCastle to create a pfx stream and then you can read that in to load the private key with the certificate. To do that on CoreCLR i used the nuget package Portable.BouncyCastle:1.8.1 with the following code i put in a helper class.
public X509Certificate2 CreateX509Certificate2(RSAParameters keys, byte[] certificateBytes, string friendlyName)
{
if (string.IsNullOrWhiteSpace(friendlyName))
{
friendlyName = "default";
}
var store = new Pkcs12Store();
var convertedKeys = GetRsaKeyPair(keys);
var certificate = new X509CertificateParser().ReadCertificate(certificateBytes);
store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(convertedKeys.Private), new X509CertificateEntry[] { new X509CertificateEntry(certificate)});
using (MemoryStream ms = new MemoryStream())
{
var random = new SecureRandom();
string password = random.Next().ToString() + random.Next().ToString() + random.Next().ToString();
store.Save(ms, password.ToCharArray(), random);
var cert = new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable);
return cert;
}
}
private AsymmetricCipherKeyPair GetRsaKeyPair(
RSAParameters rp)
{
BigInteger modulus = new BigInteger(1, rp.Modulus);
BigInteger pubExp = new BigInteger(1, rp.Exponent);
RsaKeyParameters pubKey = new RsaKeyParameters(
false,
modulus,
pubExp);
RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
modulus,
pubExp,
new BigInteger(1, rp.D),
new BigInteger(1, rp.P),
new BigInteger(1, rp.Q),
new BigInteger(1, rp.DP),
new BigInteger(1, rp.DQ),
new BigInteger(1, rp.InverseQ));
return new AsymmetricCipherKeyPair(pubKey, privKey);
}
Is there a way to set the timeout for CreateSprocAccessor(...) in Enterprise Library 5.0?
Cause the default timeout is not working for long stored procedures.
First thing: adding a timeout in the connection string doesn't solve the problem.
I found a workaround: You can modify the source code of EL 5.0 and generate a new custom DLL.
in ...\EntLib50Src\Blocks\Data\Src\Data\SprocAccessor.cs
in Execute(...) method
add this code just before return: command.CommandTimeout = 120; // 2 mins
Compile and use the new Microsoft.Practices.EnterpriseLibrary.Data.dll that you can find in ...\EntLib50Src\Blocks\bin\Debug
actually, I think there is no need to have your own copy of EL. In order to keep original EL binaries unchanged, you just can do the follow:
inherit from SprocAccessor class
overwrite Execute() method, put here the same code as in SprocAccessor.Execute() but adding the timeout part
you will need also to keep in local variable (in your new class) procedureName as this variable is private in SprocAccessor class
some thing like this:
public class SprocAccessorWithTimeout<T> : SprocAccessor<T>
{
readonly string procedureName;
public SprocAccessorWithTimeout(Database database, string procedureName, IRowMapper<T> rowMapper) : base(database, procedureName, rowMapper)
{
this.procedureName = procedureName;
}
public override IEnumerable<T> Execute(params object[] parameterValues)
{
using (var command = Database.GetStoredProcCommand(this. procedureName))
{
command.CommandTimeout = MaxSpExecutionTimeout;
if (parameterValues.Length > 0)
{
Database.AssignParameters(command, parameterValues);
}
return base.Execute(command);
}
}
}