I'm writing a conditional statement in Puppet (3.7) that tests whether the hostname is in a defined array of hostnames. If true, the class continues to run, if not, it exits with the
fail function
if $::hostname in $approved_hosts != str2bool("true") {
fail("This module is for approved reposync hosts only")
Where $approved_hosts is an array of hostnames. This method does not work, but if I change $approved_hosts to ['hostname1', 'hostname2'] it does work:
if $::hostname in ['hostname1', 'hostname2'] != str2bool("true") {
fail("This module is for approved reposync hosts only")
Can anyone explain why when I convert the array of hostnames to a variable the condition fails but works otherwise?
Thanks :)
Adjust your code (fail to notify), did the test in a test.pp file, it runs fine.
$approved_hosts = ['hostname1', 'hostname2']
if $::hostname in $approved_hosts != str2bool("true")
{ notify {"This module is for approved reposync hosts only":} }
So that means your code is no problem at array define, it should be something else.
Related
I'm using Terraform v0.14.4 with GCP. I have a Cloud Run service that won't be managed with Terraform (it might exist or not), and I want to read its url.
If the service exists this works ok:
data "google_cloud_run_service" "myservice" {
name = "myservice"
location = "us-central1"
}
output "myservice" {
value = data.google_cloud_run_service.myservice.status[0].url
}
But if it doesn't exist, I can't get it to work!. What I've tried:
data.google_cloud_run_service.myservice.*.status[*].url
status is null
length(data.google_cloud_run_service.myservice) > 0 ? data.google_cloud_run_service.myservice.*.status[0].url : ""
Tried with join("", data.google_cloud_run_service.myservice.*.status)
I get this error: data.google_cloud_run_service.myservice is object with 9 attributes
coalescelist(data.google_cloud_run_service.myservice.*.status, <...>)
It just returns [null], and using compact over the result gets me a Invalid value for "list" parameter: element 0: string required.
Any ideas?
It seems like you are working against the design of this data source a little here, but based on the error messages you've shown it seems like the behavior is that status is null when the requested object doesn't exist and is a list when it does, and so you'll need to write an expression that can deal with both situations.
Here's my attempt, based only on the documentation of the resource along with some assumptions I'm making based on the error message you included:
output "myservice" {
value = (
data.google_cloud_run_service.myservice.status != null ?
data.google_cloud_run_service.myservice.status[0].url :
null
)
}
There is another potentially-shorter way to write that, relying on the try function's ability to catch dynamic errors and return a fallback value, although this does go against the recommendations in the documentation in that it forces an unfamiliar future reader to do a bit more guesswork to understand in which situations the expression might succeed and which it might return the fallback:
output "myservice" {
value = try(data.google_cloud_run_service.myservice.status[0].url, null)
}
I have a Groovy class with a single static method:
class ResponseUtil {
static String FormatBigDecimalForUI (BigDecimal value){
(value == null || value <= 0) ? '' : roundHalfEven(value)
}
}
It has a test case or few:
#Test
void shouldFormatValidValue () {
assert '1.8' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(1.7992311))
assert '0.9' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(0.872342))
}
#Test
void shouldFormatMissingValue () {
assert '' == ResponseUtil.FormatBigDecimalForUI(null)
}
#Test
void shouldFormatInvalidValue () {
assert '' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(0))
assert '' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(0.0))
assert '' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(-1.0))
}
This results in 6/12 branches covered according to Sonar/JaCoCo:
So I've changed the code to be more...verbose. I don't think the original code is "too clever" or anything like that, but I made it more explicit and clearer. So, here it is:
static String FormatBigDecimalForUI (BigDecimal value) {
if (value == null) {
''
} else if (value <= 0) {
''
} else {
roundHalfEven(value)
}
}
And now, without having changed anything else, Sonar/JaCoCo report it to be fully covered:
Why is this the case?
I don't know if it applies to your concrete example, but keep in mind that code coverage tools typically don't work well for alternative JVM languages unless they support them explicitly. This is because virtually all of those languages generate extra byte code that may only get executed in certain cases. For example, Groovy might generate byte code for a slow path and a fast path, and might decide between them automatically, without the user having a say.
The situation might improve with Groovy 3.0, which will be designed around Java invokedynamic, meaning that less "magic" byte code will have to be generated. Meanwhile, I've heard that Clover has explicit Groovy support, although I don't know how up-to-date it is.
So, as it turns out, the Jacoco plugin for Sonar explicitly looks for Java code. I know this, as I debugged through it. It decodes the jacoco exec file and assumes any file is a JavaFile, which it doesn't find, and then says you have no coverage information.
Because of this, I grabbed the source code to the Jacoco plugin (it vanished from their Subversion repository, and never appeared on Github that I could find) and folded it into a new Groovy plugin. My updated one uses Codenarc 0.18.1 (which increases the Narc's from 32 to 305) and recognizes any kind of Jacoco file - the code in the existing plugin is unnecessarily wrong.
The source is here: https://github.com/rvowles/sonar-groovy - just build it and put it in your extensions/plugins directory.
Please don't hate me, yes I want to do something really stupid.
I want to get null on every attribute if it does not exist. I found out that I can create the propertyMissing method:
class User {
String name = "A"
}
Object.metaClass.propertyMissing() {
null
}
u = new User();
println u?.name
println u?.namee
This prints:
A
null
Now I have the "great" Hybris system in my back :D
If I add the propertyMissing part on top of my script and run this in the Hybris groovy console, I still get the MissingPropertyException.
Is there another way to avoid the MissingPropertyException exception without having to work with hundreds of try catch? (or hundreds of println u?.namee ? u.namee : null isn't working)
/Edit: 1
I have the following use case (for the Hybris system):
I want to get all necessary information in a dynamic output from some pages. Why dynamic? Some page components have the attribute headline other teaserHeadline and some other title. To avoid to create each time an try catch or if else, I created a function which loops through possible attributes and if it's null it skips that one. For that I need to return null on attributes which doesn't exist.
Here is an example which should work, but it doesn't (don't run it on your live system):
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
import de.hybris.platform.servicelayer.search.SearchResult;
flexibleSearch = spring.getBean("flexibleSearchService")
FlexibleSearchQuery query = new FlexibleSearchQuery("select {pk} from {ContentPage}");
SearchResult searchResult = flexibleSearch.search(query);
def i = 0;
def max = 1;
searchResult.result.each { page ->
if (i < max) {
gatherCMSPageInformation(page)
}
i++;
}
def gatherCMSPageInformation(page) {
page.class.metaClass.propertyMissing() {
null
}
println page.title2
}
Weird thing is, that if I run it a few times in a small interval, it starts to work. But I can't overwrite "null" to something else like "a". Also I noticed, to overwrite the Object class isn't working at all in Hybris.
/Edit 2:
I noticed, that I'm fighting against the groovy cache. Just try the first example, change null with a and then try to change it again to b in the same context, without restarting the system.
Is there a way to clear the cache?
why don't you use the groovy elvis operator?
println u?.namee ?: null
I understand at a basic level the various moving parts of build.gradle build scripts but am having trouble tying it all together.
In Apache Spark standalone mode, just trying to start a master and worker on the same box from build.gradle. (Later will extend with call with $SPARK_HOME/sbin/start-slaves with the proper argument for masterIP.)
Question: How can I assign my IP address to a variable in Groovy/build.gradle so I can pass it to a command in an Exec task? We want this to run on a couple different development machines.
We have a (I think fairly standard) /etc/hosts config with the FQDN and hostname assigned to 127.0.1.1. The driver gets around this OK but starting master and slaves with hostnames is not an option, I need the ip address.
I am trying:
task getMasterIP (type: Exec){
// declare script scope variable using no def or
executable "hostname"
args += "-I"
// need results of hostname call assigned to script scope variable
sparkMasterIP = <resultsOfHostnameCall>
}
// added this because startSlave stops if Master is already running
task startSlaveOnly(dependsOn:'getMasterIP', type: Exec){
executable "/usr/local/spark/sbin/start-slave.sh"
args += "spark://$sparkMasterIP:7077"
doLast {
println "enslaved"
}
}
// now make startSlave call startSlaveOnly after the initial startMaster
task startSlave(dependsOn:'startMaster', type: Exec) {
finalizedBy 'startSlaveOnly'
}
When I try something like suggested in the docs for Exec for Groovy calls:
task getMasterIP (type: Exec){
// declare script scope variable using no def or
sparkMasterIP = executable "hostname"
args += "-I"
}
I get a warning that executable is not recognized.
The " for a little more background on what I am thinking" section, not the main question.
Googling "build.gradle script scope variables" and looking at the first two results, in the basic docs I only see one type of variable and ext properties to be used.
16.4. Declaring variables -- There are two kinds of variables that can be declared in a build script: local variables and extra properties.
But in this other Gradle doc Appendix B. Potential Traps I am seeing two kinds of variables scopes aside from the ext properties:
For Gradle users it is important to understand how Groovy deals with
script variables. Groovy has two types of script variables. One with a
local scope and one with a script-wide scope.
With this example usage:
String localScope1 = 'localScope1'
def localScope2 = 'localScope2'
scriptScope = 'scriptScope'
I am assuming I should be using script-scope variables with no "def" or type declaration.
To fetch local IPs:
// Return all IPv4 addresses
def getLocalIPv4() {
def ip4s = []
NetworkInterface.getNetworkInterfaces()
.findAll { it.isUp() && !it.isLoopback() && !it.isVirtual() }
.each {
it.getInetAddresses()
.findAll { !it.isLoopbackAddress() && it instanceof Inet4Address }
.each { ip4s << it.getHostAddress() }
}
return ip4s
}
// Optionally, return all IPv6 addresses
def getLocalIPv6() {
def ip6s = []
NetworkInterface.getNetworkInterfaces()
.findAll { it.isUp() && !it.isLoopback() && !it.isVirtual() }
.each {
it.getInetAddresses()
.findAll { !it.isLoopbackAddress() && it instanceof Inet6Address }
.each { ip6s << it.getHostAddress() }
}
return ip6s
}
task printIP() doLast {
println getLocalIPv4()
println getLocalIPv6()
}
The two functions above return a list of IPv4 or IPv6 addresses respectively. You might notice that I'm skipping all localhosts, interfaces that are not up, all loopbacks and virtual interfaces. If you want to use the first IPv4 address, you can use it elsewhere as:
getLocalIPv4()[0]
or in your case:
args += "spark://"+ getLocalIPv4()[0] + ":7077"
I found this post that appears to be a more straightforward way of doing this but it limited to Linux platforms, hostname -I doesn't work in Windows and maybe not all Linux distros?
getting hostname
assigning it to variable
using in a build.gradle
task
Here's the task I built as a result, the accepted answer is much better and more universal, this is just for another way of looking at it
task getMasterIP{
doLast {
new ByteArrayOutputStream().withStream { os ->
def result = exec {
executable = 'hostname'
args += '-I'
}
ext.ipAddress = os.toString()
}
}
}
RaGe's answer does a better job of looking at all interfaces on all platforms
I have a Groovy class with a single static method:
class ResponseUtil {
static String FormatBigDecimalForUI (BigDecimal value){
(value == null || value <= 0) ? '' : roundHalfEven(value)
}
}
It has a test case or few:
#Test
void shouldFormatValidValue () {
assert '1.8' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(1.7992311))
assert '0.9' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(0.872342))
}
#Test
void shouldFormatMissingValue () {
assert '' == ResponseUtil.FormatBigDecimalForUI(null)
}
#Test
void shouldFormatInvalidValue () {
assert '' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(0))
assert '' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(0.0))
assert '' == ResponseUtil.FormatBigDecimalForUI(new BigDecimal(-1.0))
}
This results in 6/12 branches covered according to Sonar/JaCoCo:
So I've changed the code to be more...verbose. I don't think the original code is "too clever" or anything like that, but I made it more explicit and clearer. So, here it is:
static String FormatBigDecimalForUI (BigDecimal value) {
if (value == null) {
''
} else if (value <= 0) {
''
} else {
roundHalfEven(value)
}
}
And now, without having changed anything else, Sonar/JaCoCo report it to be fully covered:
Why is this the case?
I don't know if it applies to your concrete example, but keep in mind that code coverage tools typically don't work well for alternative JVM languages unless they support them explicitly. This is because virtually all of those languages generate extra byte code that may only get executed in certain cases. For example, Groovy might generate byte code for a slow path and a fast path, and might decide between them automatically, without the user having a say.
The situation might improve with Groovy 3.0, which will be designed around Java invokedynamic, meaning that less "magic" byte code will have to be generated. Meanwhile, I've heard that Clover has explicit Groovy support, although I don't know how up-to-date it is.
So, as it turns out, the Jacoco plugin for Sonar explicitly looks for Java code. I know this, as I debugged through it. It decodes the jacoco exec file and assumes any file is a JavaFile, which it doesn't find, and then says you have no coverage information.
Because of this, I grabbed the source code to the Jacoco plugin (it vanished from their Subversion repository, and never appeared on Github that I could find) and folded it into a new Groovy plugin. My updated one uses Codenarc 0.18.1 (which increases the Narc's from 32 to 305) and recognizes any kind of Jacoco file - the code in the existing plugin is unnecessarily wrong.
The source is here: https://github.com/rvowles/sonar-groovy - just build it and put it in your extensions/plugins directory.