From b0651723ae8487b4791b01cfbdcebf2d76907bed Mon Sep 17 00:00:00 2001 From: paulr Date: Tue, 26 Jul 2011 14:22:59 +1000 Subject: [PATCH] I updated a centos machine from this code... you ripper, it works! needs lots more error checking, woops --- libglcas/config.php | 8 + plugins/admin.php | 163 ++++++++++++++++++--- plugins/glcas_plugin.php | 2 - plugins/knownos.php | 21 ++- plugins/repo.php | 352 ++++++++++++++++++++++++++++++++++++++++++- unittests/getfilebits.php | 14 ++ unittests/repomdxmlload.php | 76 +++++++++ 7 files changed, 606 insertions(+), 30 deletions(-) create mode 100644 unittests/getfilebits.php create mode 100644 unittests/repomdxmlload.php diff --git a/libglcas/config.php b/libglcas/config.php index 634b69a..506a0b3 100644 --- a/libglcas/config.php +++ b/libglcas/config.php @@ -18,6 +18,13 @@ class GLCASConfig { } + function getConfigVar($var) + { + if(isset($this->config["$var"])) { + return $this->config["$var"]; + } else return false; + } + function setConfigVar($var, $value) { if(is_array($this->config)) { @@ -33,6 +40,7 @@ class GLCASConfig { // otherwise, set it error_log("set config of $var to $value"); $this->config[$var] = $value; + } function delConfigVar($var) diff --git a/plugins/admin.php b/plugins/admin.php index af5ed85..e6dea41 100644 --- a/plugins/admin.php +++ b/plugins/admin.php @@ -19,10 +19,26 @@ class GLCASAdmin { if(isset($_REQUEST["action"])) { switch($_REQUEST["action"]) { - case "addrepo": - GLCASpageBuilder($this,"doAddRepoForm"); + case "updaterepo": + error_log("in updaterepo"); + GLCASpageBuilder($this,"doUpdateRepo"); + return; + case "reponext": + error_log("in reponext"); + GLCASpageBuilder($this,"doRepoNextForm"); return; break; + case "addrepoyum": + GLCASpageBuilder($this,"doAddRepoYum"); + return; + case "deleterepo": + error_log("call delete repo"); + GLCASpageBuilder($this, "doRemoveRepo"); + return; + case "setstorage": + error_log("call setstorage"); + GLCASpageBuilder($this, "setStorage"); + return; case "scanrepo": break; } @@ -44,7 +60,26 @@ class GLCASAdmin { $this->mainBody($url); } - function doAddRepoForm($url) + function doRemoveRepo($url) + { + $repo = $_REQUEST["repo"]; + $myRep = new GLCASRepo($this->config); + + + error_log("called delete repo on $repo"); + $myRep->deleteRepo($repo); + + global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL; + header("Location: $BASE_URL/admin/"); + } + + + function setStorage($url) + { + + } + + function doRepoNextForm($url) { $myRep = new GLCASRepo($this->config); @@ -64,44 +99,128 @@ class GLCASAdmin { $os = $glt["OS"]; $version = $glt["version"]; $arch = $glt["arch"]; - echo "
"; - echo "OS:
"; - echo "Version:
"; - echo "Architecture:
"; - echo "Short URL
"; - echo "URL Prefix (blank for none)
"; - echo "
"; + $other = $glt["other"]; + $repourl = $_REQUEST["repourl"]; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo "
Description
OS
Version
Architecture
Other (OS, Updates, etc)
Short URL
URL Prefix (blank for none)
Do Initial Update (can take a while)
"; echo "
"; } else { // apt is much tricker cause one repo can provide multiple versions, OS's and architectures. } } + function doAddRepoYum($url) + { + $repo = new GLCASRepo($this->config); + + $desc = $_REQUEST["desc"]; + $OS = $_REQUEST["OS"]; + $version = $_REQUEST["version"]; + $arch = $_REQUEST["arch"]; + $other = $_REQUEST["other"]; + $shorturl = $_REQUEST["shorturl"]; + $prefix = $_REQUEST["prefix"]; + $repurl = $_REQUEST["repourl"]; + $init = false; + if(isset($_REQUEST["initial"])) $init = true; + + + + $repo->addRepo($desc, $OS, $version, $arch, $other, $shorturl, $prefix, $repurl, "YUM", $init); + + global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL; + header("Location: $BASE_URL/admin/"); + } + + function doUpdateRepo($url) + { + $rkey = $_REQUEST["repo"]; + + $repo = new GLCASRepo($this->config); + + $repo->updateRepo($rkey); + global $WEB_ROOT_FS, $URL_HANDLERS, $BASE_URL; + header("Location: $BASE_URL/admin/"); + } + function mainBody($url) { // first, list available repos - echo "

Repositories


"; - echo ""; + echo "

Repositories

"; + echo "
NameTypeVersionBrowseControl
"; + echo ""; + + // now iterate thru the repos and print them + $repo = new GLCASRepo($this->config); + $repos = $repo->getRepos(); + + foreach($repos as $rkey => $rval) { + $desc = $rval["desc"]; + $os = $rval["os"]; + $version = $rval["version"]; + $arch = $rval["arch"]; + $other = $rval["other"]; + $repotype = $rval["repotype"]; + $prefix = $rval["prefix"]; + $shorturl = $rval["shorturl"]; + if($prefix == "") $prefix = "-"; + if($shorturl == "") $shorturl = "-"; + echo ""; + + // get url + echo ""; + echo ""; + } + echo "
NameTypeOSVersionArchitectureOtherPrefixShort URLBrowseControl
$desc$repotype$os$version$arch$other$prefix$shorturlBrowse"; + + // Edit + echo "Edit "; + // update + echo "Update "; + // freeze + echo "Freeze "; + // deactivate + echo "Disable "; + // clean + echo "Clean "; + // Remove + echo "Delete"; + + echo "


"; + //echo "
";
+		//if($repos !== false) print_r($repos);
+		//echo "
"; // wrap all this in a table echo "
"; // now, add a repo echo "

Add A Repo

"; - echo "
"; + echo ""; echo "Type
"; echo "URL
"; echo "
"; - echo "

"; + echo ""; echo "
"; // now scan for a repo - echo "

Scan For Repos

"; + echo "

Scan For Repos - not implemented

"; echo "
"; echo "Hint
"; echo "
"; - echo "
"; + echo "
"; + + // repo storage location + echo "

Storage


"; + echo "
"; + $storloc = $this->config->getConfigVar("storagelocation"); + echo ""; + echo ""; + echo "
"; } private $config; diff --git a/plugins/glcas_plugin.php b/plugins/glcas_plugin.php index c0d36b4..5b76fd8 100644 --- a/plugins/glcas_plugin.php +++ b/plugins/glcas_plugin.php @@ -5,6 +5,4 @@ error_log("glcase_plugin loaded"); global $URL_HANDLERS; -$URL_HANDLERS["repo"] = "repo"; - ?> \ No newline at end of file diff --git a/plugins/knownos.php b/plugins/knownos.php index eda7b96..33b5bed 100644 --- a/plugins/knownos.php +++ b/plugins/knownos.php @@ -37,11 +37,16 @@ function getKnownOSList() $kos["repotype"]["apt"][0] = "baseurl"; // OS's - $kos["os"]["Fedora"] = "Fedora"; - $kos["os"]["Debian"] = "Debian"; - $kos["os"]["RedHat"] = "RedHat Enterprise Linux"; - $kos["os"]["Ubuntu"] = "Ubuntu"; - $kos["os"]["CentOS"] = "Community Enterprise OS"; + $kos["os"]["short"]["fedora"] = "Fedora"; + $kos["os"]["short"]["debian"] = "Debian"; + $kos["os"]["short"]["redhat"] = "RedHat"; + $kos["os"]["short"]["ubuntu"] = "Ubuntu"; + $kos["os"]["short"]["centos"] = "CentOS"; + $kos["os"]["fedora"]["long"] = "Fedora"; + $kos["os"]["debian"]["long"] = "Debian"; + $kos["os"]["redhat"]["long"] = "RedHat Enterprise Linux"; + $kos["os"]["ubuntu"]["long"] = "Ubuntu"; + $kos["os"]["centos"]["long"] = "Community Enterprise OS"; // Repo types per os $kos["os"]["Fedora"]["repotype"] = "yum"; @@ -50,6 +55,12 @@ function getKnownOSList() $kos["os"]["Ubuntu"]["repotype"] = "apt"; $kos["os"]["CentOS"]["repotype"] = "yum"; + // architectyres + $kos["arch"]["intel32"] = "i386"; + $kos["arch"]["amdcrazy"] = "i586"; + $kos["arch"]["amd64"] = "x86_64"; + $kos["arch"]["amd64_2"] = "amd64"; + return $kos; diff --git a/plugins/repo.php b/plugins/repo.php index fea1c4f..a703429 100644 --- a/plugins/repo.php +++ b/plugins/repo.php @@ -6,17 +6,195 @@ class GLCASRepo { function __construct($config) { $this->config = $config; + if($this->config->getConfigVar("storagelocation") == false) { + global $WEB_ROOT_FS; + $storloc = "$WEB_ROOT_FS/../var/glcas/cache/"; + if(!file_exists($storloc)) mkdir($storloc); + $this->config->setConfigVar("storagelocation", realpath($storloc)); + $this->config->saveConfig(); + error_log("set storage location, $storloc"); + } } function go($url) { error_log("repo:go called"); - GLCASpageBuilder($this, "body"); + + // figure out what we're doing + switch($url) { + case "list": + GLCASpageBuilder($this, "body"); + break; + default: + $this->getRepoForUrl($url); + } } function body($url) { - echo "for the repo, i am the repo $url"; + // this is how this will work + //$this->decodeUrl(); + if(strncasecmp("list", $url, 4)==0) { + echo "i am the repo list"; + return; + } + echo "i am the repo, $url"; + } + + function getRepoForUrl($url) + { + // the way we breakdown a url is to explode it + $xurl = split("[/,]", $url); + + // we first check if [0] is a prefix + // if now, we check for it being a shorturl (lets just do that for now) + $uconf = unserialize($this->config->getConfigVar("repodata")); + $repostore = $this->config->getConfigVar("storagelocation"); + + $matched = -1; + $startat = 0; + $prematch = false; + foreach($uconf as $key => $var) { + $pre = $var["prefix"]; + + if($pre!="") { + //echo "Checking pre $pre against ".$xurl[0]."\n"; + if(strcasecmp($pre, $xurl[0])==0) { + //echo "Matched pre\n"; + $prematch = true; + $startat++; + } + } + } + + + foreach($uconf as $key => $var) { + // if we matched a pre, then we check against the second url component + + $short = $var["shorturl"]; + + if($short!="") { + //echo "Checking short $short against ".$xurl[$startat]."\n"; + if(strcasecmp($xurl[$startat], $short)==0) { + //echo "Matched\n"; + $matched = $key; + $startat++; + } + } + } + + if($matched > -1) { + //echo "Match on $key\n"; + } + + + // now we find an actual file + $file = "/"; + if(count($xurl) > $startat) for($i=$startat; $i < count($xurl); $i++) { + $file .= "/".$xurl[$i]; + } + + // now we want to find repostore/$matched/$file; + $actualfile = "$repostore/$matched/$file"; + //echo "Start file for $actualfile\n"; + + // first check any directories in $file are in existence + $splfile = explode("/", $file); + if(count($splfile) > 1) { + $tomake = "$repostore/$matched/"; + for($i = 0; $i < count($splfile)-1; $i++) { + $tomake .= "/".$splfile[$i]; + //error_log("making directory $tomake"); + if(!is_dir($tomake)) mkdir($tomake); + } + } + + + if(is_file($actualfile)) { + // file is stored locally, away we go + header("Content-Length: ".filesize($actualfile)); + $type = mime_content_type($actualfile); + header("Content-type: $type"); + $localfile = fopen($actualfile, "r"); + while(!feof($localfile)) { + $data = fread($localfile, 16384); + echo $data; + flush(); + } + fclose($localfile); + } else if(is_dir($actualfile)) { + //echo "in dir for $actualfile\n"; + // here we print the contents of the directory + $this->printDir($actualfile, $file, $url); + } else { + // ok, get the file + //echo "in getcheck\n"; + $remotefile = $uconf[$matched]["url"]."/$file"; + + // TODO: i should get remote contents with fopen/fread/fwrite as + // it should be more memory conservative and we can push to the end client + // straight away + $rf = fopen($remotefile, "r"); + error_log("attempting to get remote file $remotefile"); + + + // hopefully this works. if we get a 30x message, it means we tried to get a directory + // i cant think of another way of dealing with it - but this is UGLY + // also get content length and content type + $clen = 0; + foreach($http_response_header as $key => $val) { + if(preg_match("/HTTP.*30[1-9].*/", $val)) { + error_log("got a 30x, must be a directory"); + mkdir($actualfile); + header("Location: ".$_SERVER["REQUEST_URI"]."/"); + return; + } + // get content length form upstream and print + if(preg_match("/^Content-Length:.*/", $val)) { + header($val); + } + // get content type from upstream and print + if(preg_match("/^Content-Type:.*/", $val)) { + header($val); + } + } + //error_log("repsonse: $http_response_header"); + if(!$rf) { + // return 404 + header("HTTP/1.0 404 Not Found"); + } else { + $localfile = fopen($actualfile.".tmp.data.deleteme", "w"); + while(!feof($rf)) { + $data = fread($rf, 8192); + echo $data; + fwrite($localfile, $data); + flush(); + } + fclose($localfile); + fclose($rf); + rename($actualfile.".tmp.data.deleteme", $actualfile); + error_log("got actualfile, tried to save as $actualfile, did it work?"); + } + } + + //echo "got ".$file." for $url which is $actualfile\n"; + + //echo ""; + } + + function printDir($dir, $localfile, $baseurl) + { + $uri = $_SERVER["REQUEST_URI"]; + if(is_dir($dir)) { + echo "Index of $localfile

Index of $localfile

"; + echo ""; + $dh = opendir($dir); + while(($file = readdir($dh))!==false) { + if($file != "." && $file != "..") echo ""; + } + echo "
$file
"; + + } else return false; } function getRepoDetailsYum($url, $ismirrorlist=false) @@ -32,13 +210,177 @@ class GLCASRepo { if(!$ld) return false; - $glt["OS"] = "Fedora"; - $glt["version"] = "15"; - $glt["arch"] = "x86_64"; + // ok, now we tokenize the url and try and guess at the content + $spurl = explode("/", $url); + // first, find the OS + $kos = getKnownOSList(); + $glt["OS"] = "unknown"; + $glt["verison"] = "unknown"; + $glt["arch"] = "unknown"; + $glt["other"] = "unknown"; + foreach($spurl as $comp) { + + // find a name + foreach($kos["os"]["short"] as $kosname => $koslong) { + //error_log("Comparing $kosname and $koslong with $comp"); + if(strcasecmp($kosname, $comp) == 0) { + //error_log("got $kosname, $koslong for $comp in $url"); + //echo "
inone\n"; print_r($koslong); echo "
"; + $glt["OS"] = $koslong; + } + } + + // find a version, we assume its going to be something [numbers] and a . (optional) + if(preg_match("/^[0-9.]+$/", $comp)>0) { + error_log("version match of $comp"); + $glt["version"] = $comp; + } + + // now architecture, this can be either i?86 or x86_64 - can also be arm or otherwise, but lets just go with this for now + foreach($kos["arch"] as $archinter => $archname ) { + //error_log("Comparing $archinter, $archname with $comp"); + if(strcasecmp($archname, $comp) == 0) { + error_log("arch match of $archname with $comp"); + $glt["arch"] = $archname; + } + } + + // other is a bt harder, we really have to guess at this one + if(strcasecmp("os", $comp) == 0) $glt["other"] = "OS"; + if(strcasecmp("update", $comp) == 0) $glt["other"] = "Updates"; + if(strcasecmp("updates", $comp) == 0) $glt["other"] = "Updates"; + if(strcasecmp("everything", $comp) == 0) $glt["other"] = "OS"; + } + + return $glt; } + function deleteRepo($rkey) + { + $uconf = $this->config->getConfigVar("repodata"); + $repostore = $this->config->getConfigVar("storagelocation"); + + if($uconf !== false) { + $conf = unserialize($uconf); + foreach($conf as $key => $vla) { + if($key == $rkey) { + unset($conf["$rkey"]); + $nconf = serialize($conf); + system("rm -rf $repostore/$key"); + error_log("remove repo as $rkey"); + $this->config->setConfigVar("repodata", $nconf); + $this->config->saveConfig(); + } + } + } + } + + function addRepo($desc, $os, $version, $arch, $other, $shorturl, $prefix, $repurl, $repotype, $init) + { + $uconf = $this->config->getConfigVar("repodata"); + + $cs["desc"] = $desc; + $cs["os"] = $os; + $cs["version"] = $version; + $cs["arch"] = $arch; + $cs["other"] = $other; + $cs["shorturl"] = $shorturl; + $cs["prefix"] = $prefix; + $cs["url"] = $repurl; + $cs["repotype"] = $repotype; + + + $ckey = 0; + if($uconf !== false) { + $conf = unserialize($uconf); + foreach($conf as $key => $val) { + $ckey = $key; + } + $ckey++; + } + + $conf[$ckey] = $cs; + + $nconf = serialize($conf); + + error_log("add repo as $ckey"); + $this->config->setConfigVar("repodata", $nconf); + $this->config->saveConfig(); + + // now create the base structure in the repo + $repostore = $this->config->getConfigVar("storagelocation"); + + + // now call update repo + if($init) $this->updateRepoYum($ckey); + } + + function updateRepo($repokey) + { + // we only do yum yet + $this->updateRepoYum($repokey); + } + + function updateRepoYum($repokey) + { + $repostore = $this->config->getConfigVar("storagelocation"); + + $repod = $this->getRepo($repokey); + + $repourl = $repod["url"]; + + if(!file_exists("$repostore/$repokey")) { + mkdir("$repostore/$repokey"); + } + + if(!file_exists("$repostore/$repokey/repodata")) { + mkdir("$repostore/$repokey/repodata"); + } + + $actionurl = "$repourl/repodata/repomd.xml"; + $repomdxml = file_get_contents($actionurl); + file_put_contents("$repostore/$repokey/repodata/repomd.xml", $repomdxml); + + $xml = simplexml_load_file("$repostore/$repokey/repodata/repomd.xml"); + + + foreach($xml as $key => $var) { + //echo "for key $key has:\n"; + //print_r($var); + if($key == "data") { + $fileloc = $var->location["href"]; + if(!file_exists("$repostore/$repokey/$fileloc")) { + error_log("getting $fileloc for $repokey on $repourl"); + $dlfile = file_get_contents("$repourl/$fileloc"); + file_put_contents("$repostore/$repokey/$fileloc", $dlfile); + } else { + error_log("Not getting $fileloc because we already have it"); + } + } + } + } + + function getRepo($id) + { + $uconf = $this->config->getConfigVar("repodata"); + if($uconf !== false) { + $lconf = unserialize($uconf); + return $lconf[$id]; + } else return false; + + } + + function getRepos() + { + $uconf = $this->config->getConfigVar("repodata"); + if($uconf !== false) { + return unserialize($uconf); + } else return false; + + } + private $config; } diff --git a/unittests/getfilebits.php b/unittests/getfilebits.php new file mode 100644 index 0000000..ce10bc7 --- /dev/null +++ b/unittests/getfilebits.php @@ -0,0 +1,14 @@ +"; print_r($http_response_header); echo ""; +while(!feof($fl)) { + $d = fread($fl, 1024); + echo $d; + flush(); +} + + + +?> \ No newline at end of file diff --git a/unittests/repomdxmlload.php b/unittests/repomdxmlload.php new file mode 100644 index 0000000..7054529 --- /dev/null +++ b/unittests/repomdxmlload.php @@ -0,0 +1,76 @@ +loadConfig($configpath); + + +// end unit test header +$repostore = $glconfig->getConfigVar("storagelocation"); + +// find a repomd.xml file +echo "
";
+$ckey =0;
+for($i=0; $i<100; $i++) {
+	//echo "Checking $repostore/$i\n";
+	if(file_exists($repostore."/$i/repodata/repomd.xml")) $ckey = $i;
+}
+
+if($ckey == 0) {
+	echo "couldnt find a ckey";
+	return;
+}
+
+$xml = simplexml_load_file($repostore."/$ckey/repodata/repomd.xml");
+
+//echo "XML $ckey is:\n";
+//print_r($xml);
+
+foreach($xml as $key => $var) {
+	//echo "for key $key has:\n";
+	//print_r($var);
+	if($key == "data") {
+		$fileloc = $var->location["href"];
+		echo "file loc to load: $fileloc\n";
+	}
+}
+
+echo "
"; + +?> \ No newline at end of file -- 1.7.0.4