I'm building a list of kubernetes resources to mak...
# kubernetes
g
I'm building a list of kubernetes resources to make easier RBAC permissions (resource - deny, instead of resource- allow all except 1), so I've made the following function, however
jsonObj
isnt blank outside of the
output.apply(...
. What am I doing wrong? If I log it inside the
output.apply(..
it behaves as expected. Some kind of scope thing I am not understanding I believe.
Copy code
export function createRbacJson() {
  // Generate list of valid resources names
  const getK8sApiOutput = new local.Command("get-k8s-api-output", {
    create: `kubectl api-resources --no-headers -o wide`,
  });

  const output = getK8sApiOutput.stdout;

  //output.apply(v => console.log(v))

  let jsonObj: any = {}

  output.apply(row =>
    row.split("\n").forEach(function (row) {
      const splitRow = row.match(/"[^"]*"|\[[^\][]*]|[^\s\][]+/g)
      if (splitRow != null) {
        const resourceName = splitRow[0]
    
        // if resource has a shortname skip it
        var columnModifier = 0
        if (splitRow.length == 6) {
          columnModifier++
        }
    
        const resourceApi = splitRow[1 + columnModifier]
        const namespaced = splitRow[2 + columnModifier]
        const resourceVerbs = splitRow[4 + columnModifier]?.replace(/[\[\]']+/g,'').split(/[ ,]+/)
        const verbs: string[] = []
        resourceVerbs.forEach(verb => {
          verbs.push(verb)
        });
        
        // console.log(resourceName)
        // console.log(resourceApi)
        // console.log(verbs)
        // console.log(namespaced)
        jsonObj[resourceName] = {
          api: resourceApi,
          verbs: verbs,
          namespaced: namespaced
        }

      }
    })
  );
  const jsonObjOutput = pulumi.output(jsonObj)

  return jsonObjOutput.apply(v => console.log(v))
}
Output of
createRbacJson()
Copy code
{}
g
An
apply
is a callback, so it doesn’t run at the same time as your other code; it runs when the input is ready. In this case, your code basically skips the apply block and returns the empty result immediately. You can fix this by returning the result of the
output.apply
directly.
Copy code
export function createRbacJson() {
  // Generate list of valid resources names
  const getK8sApiOutput = new local.Command("get-k8s-api-output", {
    create: `kubectl api-resources --no-headers -o wide`,
  });

  const output = getK8sApiOutput.stdout;

  //output.apply(v => console.log(v))

  let jsonObj: any = {}

  return output.apply(row =>
    row.split("\n").forEach(function (row) {
      const splitRow = row.match(/"[^"]*"|\[[^\][]*]|[^\s\][]+/g)
      if (splitRow != null) {
        const resourceName = splitRow[0]
    
        // if resource has a shortname skip it
        var columnModifier = 0
        if (splitRow.length == 6) {
          columnModifier++
        }
    
        const resourceApi = splitRow[1 + columnModifier]
        const namespaced = splitRow[2 + columnModifier]
        const resourceVerbs = splitRow[4 + columnModifier]?.replace(/[\[\]']+/g,'').split(/[ ,]+/)
        const verbs: string[] = []
        resourceVerbs.forEach(verb => {
          verbs.push(verb)
        });
        
        // console.log(resourceName)
        // console.log(resourceApi)
        // console.log(verbs)
        // console.log(namespaced)
        jsonObj[resourceName] = {
          api: resourceApi,
          verbs: verbs,
          namespaced: namespaced
        }

      }
    })
  );
}
g
wow awesome thanks
trying now...
do i need an apply to get jsonObj Out? that's what i wish to return from this function
1
g
I think you could initialize it inside the apply and it would work like you want.
g
so I tried your return method, but it outputs an Output<t>
so then I tried this...
console.log(createRbacJson().apply(v => v))
and its still an Output<t>
oh initialize the var to {}
how do you mean?
g
Oh, your apply isn’t returning anything. You will need to return
jsonObj
from that.
g
how? sorry
g
Something like this:
Copy code
output.apply(row => {
    row.split("\n").forEach(function (row) {
      const splitRow = row.match(/"[^"]*"|\[[^\][]*]|[^\s\][]+/g)
      if (splitRow != null) {
        const resourceName = splitRow[0]
    
        // if resource has a shortname skip it
        var columnModifier = 0
        if (splitRow.length == 6) {
          columnModifier++
        }
    
        const resourceApi = splitRow[1 + columnModifier]
        const namespaced = splitRow[2 + columnModifier]
        const resourceVerbs = splitRow[4 + columnModifier]?.replace(/[\[\]']+/g,'').split(/[ ,]+/)
        const verbs: string[] = []
        resourceVerbs.forEach(verb => {
          verbs.push(verb)
        });
        
        // console.log(resourceName)
        // console.log(resourceApi)
        // console.log(verbs)
        // console.log(namespaced)
        return jsonObj[resourceName] = {
          api: resourceApi,
          verbs: verbs,
          namespaced: namespaced
        }

      }
    })
  });
g
oh right
i see
g
Note the brackets around the function.
apply(input => { return value })
g
oh yes i missed those
hmm but on the function call i get an
.apply
does not exit for type
void
g
Since you added an explicit return, you also need to handle the
else
case
g
i switched function return type to
:any
and
console.log(createRbacJson().apply((v: any) => v))
nevermind
i dont want it to return jsonObj until the forEach is done
i think this is returning on every iteration of the forEach
i dont want to do anything if the row is null
i think i need it here?
Copy code
output.apply(row => {
    row.split("\n").forEach(function (row) {
      const splitRow = row.match(/"[^"]*"|\[[^\][]*]|[^\s\][]+/g)
      if (splitRow != null) {
        const resourceName = splitRow[0]
    
        // if resource has a shortname skip it
        var columnModifier = 0
        if (splitRow.length == 6) {
          columnModifier++
        }
    
        const resourceApi = splitRow[1 + columnModifier]
        const namespaced = splitRow[2 + columnModifier]
        const resourceVerbs = splitRow[4 + columnModifier]?.replace(/[\[\]']+/g,'').split(/[ ,]+/)
        const verbs: string[] = []
        resourceVerbs.forEach(verb => {
          verbs.push(verb)
        });
        
        // console.log(resourceName)
        // console.log(resourceApi)
        // console.log(verbs)
        // console.log(namespaced)
        jsonObj[resourceName] = {
          api: resourceApi,
          verbs: verbs,
          namespaced: namespaced
        }
      }
    })
    return jsonObj
  });
inside the new apply brackets
Copy code
const jsonObjOutput = pulumi.output(createRbacJson())
console.log(jsonObjOutput.apply(v => v))
dang still printing as an output
Copy code
OutputImpl {
      __pulumiOutput: true,
      resources: [Function (anonymous)],
      allResources: [Function (anonymous)],
      isKnown: Promise { <pending> },
      isSecret: Promise { <pending> },
      promise: [Function (anonymous)],
      toString: [Function (anonymous)],
      toJSON: [Function (anonymous)]
    }
b
you need to print the output inside the apply
g
right right
i just noticed haha
thanks!
Copy code
TypeError: Cannot read properties of undefined (reading 'apply')

createRbacJson().apply((v: any) => console.log(v))
b
no, it needs to be sometjing liike:
Copy code
jsonObjOutput.apply(v => console.log(v))
g
Copy code
undefined

const jsonObjOutput = pulumi.output(createRbacJson())
jsonObjOutput.apply(v => console.log(v))
@billowy-army-68599 @gorgeous-egg-16927
b
if its undefined the apply isn't returning anything, you'l need to do some more debugging
👍 1
g
if i replace the return with a console.log(jsonobj) it prints out fine which is interesting
but then if i do console.log(createRbacJson()) its undefined
Copy code
export function createRbacJson(): any {
  // Generate list of valid resources names
  const getK8sApiOutput = new local.Command("get-k8s-api-output", {
    create: `kubectl api-resources --no-headers -o wide`,
  });

  const output = getK8sApiOutput.stdout;

  //output.apply(v => console.log(v))

  let jsonObj: any = {}
  output.apply(row => {
    row.split("\n").forEach(function (row) {
      const splitRow = row.match(/"[^"]*"|\[[^\][]*]|[^\s\][]+/g)
...
...
        jsonObj[resourceName] = {
          api: resourceApi,
          verbs: verbs,
          namespaced: namespaced
        }
      }
    })
  console.log(jsonObj)  
  });
}
Output
Copy code
...
...
      securitygrouppolicies: {
        api: 'vpcresources.k8s.aws/v1beta1',
        verbs: [
          'delete',
          'deletecollection',
          'get',
          'list',
          'patch',
          'create',
          'update',
          'watch'
        ],
        namespaced: 'true'
      }
    }
fyi all this trouble was because i didnt know
apply
needed a
return
in the function 🤦‍♂️