-7

I get these errors

Use of uninitialized value $vm_name in pattern match (m//) at testscript.pl line 164, <STDIN> line 1.

Use of uninitialized value $vm_name in concatenation (.) or string at testscript.pl line 173, <STDIN> line 1.

Can anyone help? I have a feeling it is to do with the subroutine but cannot figure it out exactly. I am new to Perl and have been poring over this for hours.

# !/usr/bin/perl

use strict;
use warnings;
use feature ":5.10";

###############################################################################
# Static Variables
my $templateID = "XXXXXXXXXX";
my $serviceID  = "XXXXXXXXXXX";
###############################################################################

###############################################################################
# Global Variables
my $zone;
my $input;
my $zone_ID;
my $vm_name;
my $net_default;
my $net_secondary;
my $vm_ID;
my $start;
my $char_count;
my $ipaddr_1;
my $ipaddr_2;
###############################################################################

# ----------------------- BASIC CONFIGURATIONS [ZONES] ------------------------

print " *** ";
print "
ZONES: paris, milan, berlin, geneva, amsterdam, london, slough";
print " which zone would you like to deploy to? \n ";

# Capture input for ZONE
$input = <STDIN>;

# Data formatting
$input =~ s/^\s+|\s+$|^\t//g;
$zone = lc $input;

# Declare ZONE to USER
print "You are deploying to $zone \n";

# Map input to function

# ZONE PARIS
if ($zone eq "paris") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "374b937d-2051-4440-b02c-a314dd9cb27e";
}

# ZONE MILAN
elsif ($zone eq "milan") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "58848a37-db49-4518-946a-88911db0ee2b";
}

# ZONE BERLIN
elsif ($zone eq "berlin") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "fc129b38-d490-4cd9-acf8-838cf7eb168d";
}

# ZONE GENEVE
elsif ($zone eq "geneva") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "1ef96ec0-9e51-4502-9a81-045bc37ecc0a";
}

# ZONE AMSTERDAM
elsif ($zone eq "amsterdam") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "3c43b32b-fadf-4629-b8e9-61fb7a5b9bb8";
}

# ZONE SLOUGH
elsif ($zone eq "slough") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "5343ddc2-919f-4d1b-a8e6-59f91d901f8e";
}

# ZONE LONDON
elsif ($zone eq "london") {
   print "Deploying to $zone\n";
   # assign zone id
   $zone_ID = "f6b0d029-8e53-413b-99f3-e0a2a543ee1d";
}

# ELSE
else {
   print "Please choose a ZONE";
   system('./deploy_vm');
}

# SUBROUTINE: Assigning Virtual Machine name
sub vm_name {

   # Name of Virtual Machine
   print "Enter name of Virtual Machine: \n";
   print "[VDC Bug: Please do not include '_' in the name]\n";
   my $vm_name = <STDIN>;

   # Data formatting
   $vm_name =~ s/^\s+|\s+$//g;
   print("VM Name: $vm_name");

}

# Apply input filters (no underscores, length constraints)
if (my $vm_name =~ /_/) {
   return ('underscore error');
   print "Cannot use underscore in VM name, please try again";
   vm_name();
}

# DisPlay config
print "
$vm_name will be provisioned with:
1GB HDD and compute offering of 2CPUs with 2GB-RAM";

# ----------------------- NETWORK CONFIGURATIONS ------------------------------

# Gather network information
print "available networks in $zone";
system('cloudmonkey list networks zoneid=$zone_id filter=name,id');

# Users to choose Networks through display
print "";

# Default NIC & IP address
print "please enter Network ID for Default NIC:\n";
$net_default = <STDIN>;

# IP Address DEFAULT
print "please enter IP address\n";
$ipaddr_1 = <STDIN>;

# formatting IP address
$ipaddr_1 =~ m/^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/;

# SECONDARY NIC & IP address
print "please enter Network ID for secondary NIC";
$net_secondary = <STDIN>;

# IP Address SECONDARY
print "please enter IP address\n";
$ipaddr_2 = <STDIN>;

# Formatting IP address
$ipaddr_2 =~ m/^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/;

print "IP ADDRESS is $ipaddr_2\n";

# Deployment notice
print "... deploying ... \n";

# Provision Machine

# + startvm=false due to provisioning constraints

system('cloudmonkey deploy virtualmachine startvm=false name=$vm_name diplayname=$vm_name zoneid=$zone_id templateid=$templateID serviceofferingid=$serviceID networkids=$net_default ipaddress=$ipaddr_1');

# Add second network to VM
print "Adding second network to VM";
system('cloudmonkey addNicToVirtualMachine networkid=$network_id_second ipaddress=$ip_address_second virtualmachineid=$vm_id');

# Display machine ID
print "$vm_ID";
my $feedback = system('cloudmonkey list networks zoneid=$zone_id filter=name,id');

# ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
# #     Sotiris Comments     # #
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
# if (lc($feedback) =~ /error/) {
#    Warn user and fall back to known state. }

# User to copy&paste ID
print "Paste VM ID:\n";
$vm_ID = <STDIN>;

# Data Validation
$vm_ID      =~ s/^\s+|\s+$//g;
$vm_ID      = lc $vm_ID;
$char_count = length($vm_ID);

# IF statement to impliment length validation
if ($char_count != 36) {
   print "your ID is too long/short";
}

# Start Virtual Machine?
print "Start Virtual Machine $vm_name?";
$start = <STDIN>;

if ($start eq "yes") {
   system('');
}
elsif ($start eq "no") {
   system('');
}

# done!
Community
  • 1
  • 1
3c75
  • 17
  • 5
  • You have to tell us which line is 164 and 173. – TLP Oct 07 '14 at 13:53
  • 1
    Your error messages don't line up with your code. – nobody Oct 07 '14 at 13:55
  • My apologies, line 164 is the code that starts directly beneath the #Apply input filters (no underscores, length constraints) heading and line 173 is the code right under the #Dislay config heading directly after – 3c75 Oct 07 '14 at 14:11
  • Guys please take it easy on the negative votes, Im new to all this – 3c75 Oct 07 '14 at 14:13
  • 7
    @3c75 The negative votes come from pasting a whole file into the question. It shows little effort has been made to pinpoint the error. – TLP Oct 07 '14 at 14:29
  • @TLP thats only to make it easier for someone to pinpoint where I went wrong, what if I isolated a small bit and it turned out my error was caused above the lines of code I provided? I had no idea where the problem was... I'm assuming then that I'd also get negative votes if the code didnt contain the cause error :/ – 3c75 Oct 07 '14 at 14:42
  • 1
    @TLP: There is no problem with posting large amounts of code. The problem is in *writing* that amount of code before testing it, and being unsure of where the problem may lie in that expanse – Borodin Oct 07 '14 at 14:51
  • @3c75q: While I know it's hard to perceive them otherwise, the negative votes aren't personal, but are about refining the content of Stack Overflow that is helpful to others without being repetitive. I presume you will agree that your question and its answers would be of little aid to others searching the site for any keywords in your subject line? – Borodin Oct 07 '14 at 15:05
  • @3c75 That is a good point, and that happens sometimes as well, but you are less likely to get downvotes, because you have made an effort. It is not a bad thing to be wrong, but it is a bad thing to be lazy. You can also include all of your code if you want, so long as you have given sufficient information about where the relevant parts are (such as the lines where errors occur). In general, you should strive to create an [sscce](http://sscce.org): A Short, Self Contained, Correct (Compilable) Example that demonstrates and replicates the errors you have given. – TLP Oct 07 '14 at 15:40

3 Answers3

4

You have posted a poor piece of Perl code that you have presumably written all in one chunk. Programming doesn't work like that, especially in script-like languages, and you should write just two or three lines at a time before testing that it works as you expect. That way, if you have a question at all, it can be about just a few lines of code whose input you know but whose behaviour you can't explain. In this case your Use of uninitialized value errors are the least of your worries.

  • You really shouldn't delcare everything at the top of your program, C-style. Declarations should be as close as possible to their first point of use.

  • Comments should be kept to the absolute minimum. It is very rare that a program contains a construct that is incomprehensible without the addition of comments, and your program is inflated around 100% by unnecessary commenting

  • The mapping between zones and zone IDs is best implemented as a Perl hash, not as an if/elsif/else chain

  • The vm_name subroutine is never called except in the test if (my $vm_name =~ /_/) { ... }, and your use of my here declares a new $vm_name which will always be undef

  • The lines you have commented with formatting IP address do no formatting at all. They test whether the variables' contents match the regular expression, and then ignore and discard the result of the test

  • The calls to system use single quotes, so the string is passed verbatim to the cloudmonkey program, and no interpolations are done. For instance, the variable names $vm_name, $zone_id, $templateID, $serviceID etc. are not replaced by their values

There are several more problems, but I strongly suggest that, as I said at the start, you should write the program incrementally in very small parts. That way you have the encouraging pleasure of seeing your code in action and wortking, as well as knowing for sure that, as you write, you have a firm foundation to build on.

Borodin
  • 126,100
  • 9
  • 70
  • 144
  • Thank you! I did write this one small bit at a time, but when I tried compiling into one module things started falling apart :( - but thanks for your advice, something other than negative votes I can learn from – 3c75 Oct 07 '14 at 14:53
  • 1
    Then you haven't written and tested your code thoroughly and in small-enough parts. Certainly the pieces that I have highlighted have *not* been tested. Please do it: it will be encouraging to see your code work! You don't need to use Perl modules for something as small as this. And it is counter-productive just to declare a bunch of file-global variables as you will be troubled by multiple-use problems. You may prefer Stack Exchange's [Code Review site](http://codereview.stackexchange.com/) as they tend to be less critical that Stack Overflow, which is a site for programming professionals. – Borodin Oct 07 '14 at 15:00
1
if (my $vm_name =~ /_/)

will always warn Use of uninitialized value $vm_name in pattern match under warnings, as you're mistakenly declaring another lexical with my inside if condition.

Also you should sanitize user input as

my $vm_name = <STDIN>;

returned undefined if the user presses Ctrl-D or there was end of piped input.

mpapec
  • 50,217
  • 8
  • 67
  • 127
  • Hi Mpapec, is there another way perhaps in which I can look for an _ in the input and let the user know that they cannot use this character when naming their Virtual device (without the warnings?) – 3c75 Oct 07 '14 at 14:23
  • 2
    @3c75, just remove the two little letters `my`. – tobyink Oct 07 '14 at 14:24
  • You should change the order of your two main points: It is the `my` that is causing the error, so it should come first. – TLP Oct 07 '14 at 14:36
  • @ikegami `perl -E 'say // "undef!"'` and ctrl+z? – mpapec Oct 07 '14 at 14:39
0

You're reached the end of the input, but you pretend you actually read something in. Maybe you want to add

die "Premature EOF\n" if !defined($vm_name);

after

my $vm_name=<STDIN>;
ikegami
  • 367,544
  • 15
  • 269
  • 518