https://pulumi.com logo
#kubernetes
Title
# kubernetes
g

glamorous-australia-21342

06/14/2022, 3:25 PM
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

gorgeous-egg-16927

06/14/2022, 3:35 PM
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

glamorous-australia-21342

06/14/2022, 3:36 PM
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

gorgeous-egg-16927

06/14/2022, 3:38 PM
I think you could initialize it inside the apply and it would work like you want.
g

glamorous-australia-21342

06/14/2022, 3:38 PM
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

gorgeous-egg-16927

06/14/2022, 3:39 PM
Oh, your apply isn’t returning anything. You will need to return
jsonObj
from that.
g

glamorous-australia-21342

06/14/2022, 3:40 PM
how? sorry
g

gorgeous-egg-16927

06/14/2022, 3:40 PM
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

glamorous-australia-21342

06/14/2022, 3:40 PM
oh right
i see
g

gorgeous-egg-16927

06/14/2022, 3:41 PM
Note the brackets around the function.
apply(input => { return value })
g

glamorous-australia-21342

06/14/2022, 3:41 PM
oh yes i missed those
hmm but on the function call i get an
.apply
does not exit for type
void
g

gorgeous-egg-16927

06/14/2022, 3:43 PM
Since you added an explicit return, you also need to handle the
else
case
g

glamorous-australia-21342

06/14/2022, 3:43 PM
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

billowy-army-68599

06/14/2022, 3:53 PM
you need to print the output inside the apply
g

glamorous-australia-21342

06/14/2022, 3:53 PM
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

billowy-army-68599

06/14/2022, 3:56 PM
no, it needs to be sometjing liike:
Copy code
jsonObjOutput.apply(v => console.log(v))
g

glamorous-australia-21342

06/14/2022, 3:57 PM
Copy code
undefined

const jsonObjOutput = pulumi.output(createRbacJson())
jsonObjOutput.apply(v => console.log(v))
@billowy-army-68599 @gorgeous-egg-16927
b

billowy-army-68599

06/14/2022, 4:12 PM
if its undefined the apply isn't returning anything, you'l need to do some more debugging
👍 1
g

glamorous-australia-21342

06/14/2022, 4:15 PM
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 🤦‍♂️
7 Views