Pulumi ensure dependency order - pulumi

I need a way of ensuring some services have been stood up and their URLs formalised in GCP before I craft an OpenAPI spec - using substitutions. The URLs are relatively dynamic as this environment is torn down nightly.
One solution I have is
import { helloWorldUrl } from './cloud-run/hello-world';
import { anotherHelloWorldUrl } from './cloud-run/another-hello-world-service';
import * as pulumi from '#pulumi/pulumi';
import * as fs from 'fs';
import * as Mustache from 'mustache';
pulumi.all([helloWorldUrl, anotherHelloWorldUrl])
.apply(([hello, another]) => {
let gatewayOpenAPI = fs.readFileSync('./api-gateway/open-api/gateway.yaml').toString();
gatewayOpenAPI = Mustache.render(gatewayOpenAPI, { helloWorldUrl: hello, anotherHelloWorld: another });
fs.writeFileSync(`./api-gateway/open-api/gateway-${pulumi.getStack()}.yaml`, gatewayOpenAPI);
// create api gateway infra here.
// cannot return outputs here :(
});
but this does not allow me to set Outputs. Is there a more elegant solution to this?
Cheers
KH

If you want to have a strict dependency order, you should use Pulumi Component Resources. You can then pass in your URLs as an input to the component resource, and access any outputs created by this component resource. You should also note that it's not allowed to create any resources in the callback of the apply method.
You might find the following example helpful to see the component resources in action: https://www.pulumi.com/registry/packages/aws/how-to-guides/s3-folder-component/

Related

Error using CLI for cloud functions with IAM namespaces

I'm trying to create an IBM Cloud Function web action from some python code. This code has a dependency which isn't in the runtime, so I've followed the steps here to package the dependency with my code. I now need to create the action on the cloud for this package, using the steps described here. I've got several issues.
The first is that I want to check that this will be going into the right namespace. However though I have several, none are showing up when i do ibmcloud fn namespace list, I just get the empty table with headers. I checked that I was targeting the right region using ibmcloud target -r eu-gb.
The second is that when I try to bypass the problem above by creating a namespace from the command line using ibmcloud fn namespace create nyNamespaceName, it works, but I then check on the web UI, and this new namespace has been created in the Dallas region instead of the London one… I can’t seem to get it to create a namespace in the region that I am currently targeting for some reason, it’s always Dallas.
The third problem is that when I try to follow the steps 2 and 3 from here regardless, accepting that it will end up in the unwanted Dallas namespace, by running the equivalent of ibmcloud fn action create demo/hello <filepath>/hello.js --web true, it keeps telling me I need to target an org and a space. But my namespace is an IAM namespace, it doesn’t have an org and a space, so there are none to give?
Please let me know if I’m missing something obvious or have misunderstood something, because to me it feels like the CLI is not respecting the targeting of a region and not handling IAM stuff correctly.
Edit: adding code as suggested, but this code runs fine locally, it's the CLI part that I'm struggling with?
import sys
import requests
import pandas as pd
import json
from ibm_ai_openscale import APIClient
def main(dict):
# Get AI Openscale GUID
AIOS_GUID = None
token_data = {
'grant_type': 'urn:ibm:params:oauth:grant-type:apikey',
'response_type': 'cloud_iam',
'apikey': 'SOMEAPIKEYHERE'
}
response = requests.post('https://iam.bluemix.net/identity/token', data=token_data)
iam_token = response.json()['access_token']
iam_headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer %s' % iam_token
}
resources = json.loads(requests.get('https://resource-controller.cloud.ibm.com/v2/resource_instances', headers=iam_headers).text)['resources']
for resource in resources:
if "aiopenscale" in resource['id'].lower():
AIOS_GUID = resource['guid']
AIOS_CREDENTIALS = {
"instance_guid": AIOS_GUID,
"apikey": 'SOMEAPIKEYHERE',
"url": "https://api.aiopenscale.cloud.ibm.com"
}
if AIOS_GUID is None:
print('AI OpenScale GUID NOT FOUND')
else:
print('AI OpenScale FOUND')
#GET OPENSCALE SUBSCRIPTION
ai_client = APIClient(aios_credentials=AIOS_CREDENTIALS)
subscriptions_uids = ai_client.data_mart.subscriptions.get_uids()
for sub in subscriptions_uids:
if ai_client.data_mart.subscriptions.get_details(sub)['entity']['asset']['name'] == "MYMODELNAME":
subscription = ai_client.data_mart.subscriptions.get(sub)
#EXPLAINABILITY TEST
sample_transaction_id="SAMPLEID"
run_details = subscription.explainability.run(transaction_id=sample_transaction_id, cem=False)
#Formating results
run_details_json = json.dumps(run_details)
return run_details_json
I know the OP said they were 'targeting the right region'. But I want to make it clear that the 'right region' is the exact region in which the namespaces you want to list or target are located.
Unless you target this region, you won't be able to list or target any of those namespaces.
This is counterintuitive because
You are able to list Service IDs of namespaces in regions other than the one you are targeting.
The web portal allows you to see namespaces in all regions, so why shouldn't the CLI?
I was having an issue very similar to the OP's first problem, but once I targeted the correct region it worked fine.

How to extend confluence autocomplete-content

I try to extend autocomplete-content macro by own logic witch should be call some rest.
I finded autocomplete-content.js file where autocomplete-content is defined, but I dont have idea how to extend it by own autocompleteModule.
I tried create own JS file as resource in own add-on, but it execute before autocomplete-content.js on confluence, and autocompleteContent object was undefined.
In the end I need to have own autocomplete tool with own rest service witch will be fatch data from other DB.
If possible use AUI Select2.
Please note: AUI Select2 is based on older Select2. You have to refer to this documentation: http://select2.github.io/select2/
Something else would be to use QuickSearchDropDown
It is not really documented, but quite easy to use. Look for a file quicksearchdropdown.js in Confluence sources.
You can use it like this:
AJS.$('#myinput').quicksearch(URL_RELATIVE_TO_CONFLUENCE_BASE, false, {
makeParams: function (params) {
return {
username: params.term,
staticParam: 'blabla'
};
}
}

sails.js - How can I specify an order to the routes of installable hooks?

I have a few policies that I'm trying to convert to installable hooks.
One in particular is the authentication step that adds a session variable for who the user is. I need to ensure that it fires first because subsequent hooks/controllers look at the session to determine who the user is.
The docs on routes ( https://github.com/balderdashy/sails-docs/blob/master/concepts/extending-sails/Hooks/hookspec/routes.md ) say that I can specify if I want to run the route before or after all the custom routes, but I don't see a way to specify one hook before another hook.
I tried adding a "sails.on" in the initialize step of my two hooks as specified in the initialize docs ( https://github.com/balderdashy/sails-docs/blob/master/concepts/extending-sails/Hooks/hookspec/initialize.md ). While it did alter the order of the initialize phase, it didn't seem to have any impact on the order that routes were handled.
Any pointers would be greatly appreciated.
As you noted, there's no way to re-order hooks at the moment, but that doesn't mean you can't accomplish your goal in another way. The routes feature of hooks is very convenient, but in this case you will need to bind your routes using events, and then make your hooks dependent on each other to ensure that the routes load in the correct order. Many of the core Sails hooks work in just this way.
If you want to ensure that the hook firsthook to loads all of its routes before secondhook, you would put the following as the initialize method of firsthook:
initialize: function(cb) {
sails.on('router:before', function () {
sails.router.bind(routePath1, routeFn1);
sails.router.bind(routePath2, routeFn2);
sails.router.bind(routePath3, routeFn3);
etc...
});
}
And then do the same in secondhook, but wrapped in a sails.after block:
initialize: function(cb) {
sails.after('hook:firsthook:loaded', function() {
sails.on('router:before', function () {
sails.router.bind(routePath1, routeFn1);
sails.router.bind(routePath2, routeFn2);
sails.router.bind(routePath3, routeFn3);
etc...
});
}
}
Note that sails.after can accept either a single event name or an array to wait for.

Scala - play2 config get section

I decided to try scala out with play2. I am trying to somehow get a config section out of application config. It looks like this (by section I mean whole mail part)
services: {
rest: {
mail: {
uri: "xyz",
authorization: {
username: "xyz",
password: "xyz"
}
}
}
}
Code
import com.typesafe.config.ConfigObject
import play.api.Play.current
val config: Option[ConfigObject] = current.configuration.getObject("services.rest.mail")
This gives Some(SimpleConfigObject()) and trough there the only way I am able to actually get mail section and use it as a ConfigObject is trough
config.get.toConfig.getString("uri")
Or I can get the actual value with
config.get.get("uri").unwrapped().toString
Or for fun:
config.get.toConfig.getObject("authorization").toConfig.getString("username")
Either way it seems to me I am doing it overly complicated. Is there some easier way to get a section from config?
Since the config library has a Java API, it can feel a bit verbose using it from Scala. There are some Scala wrappers though that enable more compact syntax. See https://github.com/typesafehub/config#scala-wrappers-for-the-java-library.
I will post this as an answer for future reference.
After another while of playing with the code I have found parseResourcesAnySyntax method which does exactly what I want and since I have my config split into multiple parts for separate environments (application.dev.conf, etc.) I can simply do
import com.typesafe.config.{Config, ConfigFactory}
import play.api.Play._
val config: Config = ConfigFactory.parseResourcesAnySyntax("application.%s.conf" format current.mode)
and then use
config.getString("uri")
// or
config.getString("authorization.username")
// or if I want to use part of it as another section
val section: Config = config.getConfig("authorization")
section.getString("username")
Of course, another viable alternative is using a wrapper as mister Stebel recommended.

CQ - Moving content from one page to another

I realize that this is a pretty specific question but I would imagine someone has run into this before. So I've got about fifty pages or so that were created about a year ago. We're trying to revamp the page with new components specifically in the header and the footer. Except the content in the main-content area will stay the same. So I'm trying to move over everything from the old pages to the new pages but just keep the main-content area. The problem is I can't just change the resource type on the old page to point to the new page components because the content is different and I'll have a bunch of nodes in the header and footer that I don't want. For example here is my current content structure:
Old Content
star-trek
jcr:content
header
nav
social
chat
main-content
column-one
column-two
footer
sign-up
mega-menu
New Content
star-wars
jcr:content
masthead
mega-menu
main-content
column-one
column-two
bottom-footer
left-links
right-links
Does anybody have any ideas on how to move just the content in the main-content node and somehow remove the other nodes. I'm trying to somehow do this programmatically cause I don't want to create 50 pages from scratch. Any help is appreciated!
You can use the JCR API to move things around at will, I would
Block users from accessing the content in question. Can be done with temporary ACLs, or by closing access on the front-end if you can.
Run a script or servlet that changes the content using JCR APIs
Check the results
Let users access the content again
For the content modification script I suggest a script that modifies a single page (i.e. you call it with an HTTP request that ends in /content/star-trek.modify.txt) so that you can run it either on a single page, for testing, or on a group of pages once it's good.
The script starts form the current node, recurses into it to find nodes that it knowns how to modify (based on their sling:resourceType), modifies them and reports what it did in the logs or on its output.
To modify nodes the script uses the JCR Node APIs to move things around (and maybe Worskpace.move).
It is indeed possible to write a code which does what you need :
package com.test;
import java.io.File;
import java.io.IOException;
import javax.jcr.ItemExistsException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Node;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.jackrabbit.core.TransientRepository;
import org.xml.sax.SAXException;
public class test {
public void test(Document doc) throws RepositoryException {
try {
// Create a connection to the CQ repository running on local host
Repository repository = JcrUtils
.getRepository("http://localhost:4502/crx/server");
System.out.println("rep is created");
// Create a Session
javax.jcr.Session session = repository.login(new SimpleCredentials(
"admin", "admin".toCharArray()));
System.out.println("session is created");
String starTrekNodePath = "/content/path/";
String starWarsNodePath = "/content/anotherPath"
Node starTrekpageJcrNode = null;
Node starWarstext = null;
setProperty(java.lang.String name, Node value)
boolean starTrekNodeFlag = session.nodeExists(starTrekNodePath);
boolean starWarsNodeFlag = session.nodeExists(starWarsNodePath);
if (starTrekNodeFlag && starWarsNodeFlag) {
System.out.println("to infinity and beyond");
Node starTrekNode = session.getNode(starTrekNodePath);
Node starWarsNodeFlag = session.getNode(starWarsNodePath);
//apply nested looping logic here; to loop through all pages under this node
//assumption is that you have similar page titles or something
//on these lines to determine target and destination nodes
//2nd assumption is that destination pages exist with the component structures in q
//once we have the target nodes, the following segment should be all you need
Node starTrekChildNode = iterator.next();//assuming you use some form of iterator for looping logic
Node starWarsChildNode = iterator1.next();//assuming you use some form of iterator for looping logic
//next we get the jcr:content node of the target and child nodes
Node starTrekChildJcrNode = starTrekChildNode.getNode("jcr:content");
Node starWarsChildJcrNode = starWarsChildNode.getNode("jcr:content");
// now we fetch the main-component nodes.
Node starTrekChildMCNode = starTrekChildJcrNode.getNode("main-content");
Node starWarsChildMCNode = starWarsChildJcrNode.getNode("main-content");
//now we fetch each component node
Node starTrekChildC1Node = starTrekChildMCNode.getNode("column-one");
Node starTrekChildC2Node = starTrekChildMCNode.getNode("column-two");
Node starWarsChildC1Node = starWarsChildMCNode.getNode("column-one");
Node starWarsChildC2Node = starWarsChildMCNode.getNode("column-two");
// fetch the properties for each node of column-one and column-two from target
String prop1;
String prop2;
PropertyIterator iterator = starTrekChildC1Node.getProperties(propName);
while (iterator.hasNext()) {
Property prop = iterator.nextProperty();
prop1 = prop.getString();
}
PropertyIterator iterator = starTrekChildC2Node.getProperties(propName);
while (iterator.hasNext()) {
Property prop = iterator.nextProperty();
prop2 = prop.getString();
}
// and now we set the values
starWarsChildC1Node.setProperty("property-name",prop1);
starWarsChildC2Node.setProperty("property-name",prop2);
//end loops as appropriate
}
Hopefully this should set you on the right track. You'd have to figure out how you want to identify destination and target pages, based on your folder structure in /content, but the essential logic should be the same
The problem with the results I'm seeing here is that you are writing servlets that execute JCR operations to move things around. While technically that works, it's not really a scalable or reusable way to do this. You have to write some very specific code, deploy it, execute it, then delete it (or it lives out there forever). It's kind of impractical and not totally RESTful.
Here are two better options:
One of my colleagues wrote the CQ Groovy Console, which gives you the ability to use Groovy to script changes to the repository. We frequently use it for content transformations, like you've described. The advantage to using Groovy is that it's script (not compiled/deployed code). You still have access to the JCR API if you need it, but the console has a bunch of helper methods to make things even easier. I highly recommend this approach.
https://github.com/Citytechinc/cq-groovy-console
The other approach is to use the Bulk Editor tool in AEM. You can export a TSV of content, make changes, then reimport. You'll have to turn the import feature on using an administrative function, but I've used this with some success. Beware, it's a bit buggy though, with array value properties.